Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1412114 Posts in 69451 Topics- by 58491 Members - Latest Member: tzdevil

June 28, 2024, 10:34:41 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsCommunityDevLogsSpider Game - no-gravity puzzle platformer, explore geometrical spaces
Pages: 1 [2]
Print
Author Topic: Spider Game - no-gravity puzzle platformer, explore geometrical spaces  (Read 3921 times)
bayersglassey
Level 0
***



View Profile
« Reply #20 on: December 20, 2021, 11:57:34 PM »

Playing the tutorial recently, I found the spider's movement to be a bit slow, and wished there was a run button.
It's not just the movement speed, but the fact that for much of the tutorial, you just need to "hold forward": it's trying to teach you how you will automatically crawl around "smooth curves", as it were.
So after you've played the tutorial a billion times during testing, you find it pretty dull.
It wouldn't be so bad if you had more movement options available to you -- more "things to do".
For instance, playing Hollow Knight recently I found the walking speed to be pretty slow, but at least you can hammer on the jump and slash buttons, so you're "doing something" even while walking slowly forwards.
Metroid games often have even more movement options, e.g. morph ball.
In the spider game, you can't "jump repeatedly" as you travel, because there's no gravity so you can only "jump" forwards, the same direction you would have been walking.

So, I decided I want to have a way to make the spider run.
It should be optional, because many people find the controls confusing enough even at the current speed.
I think if you're moving forward, and you tap the "up" arrow key, you should start to run.
So now I need to figure out how to fit that into the current "stateset" (see previous post).
It's been a while since I've made any big changes to the spider's movement, and the spider's stateset's code is a ball of spaghetti (see the "_spider*.fus" files in https://github.com/bayersglassey/geom2018/tree/master/anim/), so I wrote a tool to read in a stateset and output a graph / diagram of it (using Graphviz's "dot" language -- all praise to Graphviz).

Behold!



...that's not too bad, but actually things get more complicated if you consider the statesets for the various kinds of spider (which are all defined by the same set of files, but with if-statements checking for what kind of spider the current stateset is for, turning various states and rules on or off accordingly).

Here are the different types of spider at the moment:


(...the last one's not really a spider, it's a "purple person", but his stateset is mostly defined by the same files as the spiders' statesets.)

The spider whose nose is a bit longer than the others is the "aimerspider", and holding the shift key as that spider causes him to "aim" (tilt his head) upwards.
Accordingly, his stateset has a bunch of extra states with a "looking_up_" prefix:

Aimerspider's stateset


That shows the complete set of states a "running" feature would need to be integrated with, because you probably need to be able to look up while running.

I think the solution will be...
The "start_jump" state needs to check if you're holding forward, in which case it transitions you to a new "running_jump" state, instead of just "jump".
And then we need to make "running_"-prefixed copies of the states "stand", "step", "step_down", "step_up", and any "looking_up" variations of those...
I think that gets us 90% of the way there. That's not so bad, actually.
« Last Edit: December 21, 2021, 12:08:58 AM by bayersglassey » Logged
a-k-
Level 2
**


View Profile
« Reply #21 on: December 28, 2021, 03:51:57 PM »

No query string cheats like in your other game? I may need to remove a few "goto :dead"...
Logged

bayersglassey
Level 0
***



View Profile
« Reply #22 on: January 16, 2022, 12:33:20 PM »

No query string cheats like in your other game? I may need to remove a few "goto :dead"...

Hah, this game's written in C, and usually I run it from the commandline. So the equivalent of query parameters here is commandline options:


$ bin/demo --help
Options:
   -h   --help           Shows this message
   -F                    Fullscreen mode
   -FD                   Software simulated fullscreen mode
   -f            FILE    Prismelrenderer filename (default: data/test.fus)
   -a   --anim   FILE    Stateset filename (default: anim/spider.fus)
   -m   --map    FILE    Map filename (default: NULL)
   -sm  --submap FILE    Submap filename (default: NULL)
   -D   --devel          Developer mode
                         (You can also use env var HEXGAME_DEVEL)
   -d   --delay     N    Delay goal (in milliseconds) (default: 30)
   -p   --players   N    Number of players (default: 1)
   -l   --load           Load/continue game immediately (skip title screen)
        --minimap_alt    Use alternate minimap
        --dont_cache_bitmaps
                         ...low-level hokey-pokery, should probably get rid of this option


When the game is in a browser, that's cos I compiled it with Emscripten (C to JS).
I have thought before about trying to turn query parameters into commandline options, but there wouldn't be much payoff for me, because I just run it from commandline to begin with. Smiley

That said, there are some "cheats" available in-game via the F keys (F6 etc), and a console, but only if a certain commandline option is passed (see --devel above).
I could definitely edit the Emscripten build's HTML page to look for a "devel" query parameter and, if present, pass that along to the game somehow.
But the F keys don't play well with browsers, generally speaking... e.g. the game uses F5 for pause/unpause (so you can step through it frame-by-frame using PageUp key), but in a browser that'll probably refresh the page.

So... you'll need to build the game if you want to use the "cheats"... just need GCC and the SDL2 dev libraries installed, and then run "make" to compile, and "bin/demo" to run the game! :D


Edit: here's the in-game console, it's pretty rough:

...it works well enough for simple things like changing your player from one type of spider to another on the fly, or inspecting various low-level things while the game is running...
« Last Edit: January 16, 2022, 12:42:01 PM by bayersglassey » Logged
bayersglassey
Level 0
***



View Profile
« Reply #23 on: January 16, 2022, 12:55:10 PM »

Update! Hooray.
I've made a lot of changes to the engine over the past couple of months!



The minimap

  • Displaying the minimap pauses the game now
  • It can be zoomed in or out (not smoothly, rather it can either be in zoomed-in or zoomed-out mode)
  • The game now tracks which parts of the map you've seen, and that information is saved/loaded when you save/load the game


Video showing off the minimap:






Maps of the first 2 parts of the tutorial






Maps of the main part of the game after the tutorial









The menu

The game now has a menu!.. there are 3 save slots, and you can load a game or start a new game at any time via the menu.
It's not a very pretty menu, but because it's just text, I can probably add a way to render fancy text, and suddenly have a prettier menu.
Specifically, I want to render text in a font made out of "prismels" (see previous posts), i.e. squares & triangles instead of just squares. Because that's the theme!








The controls

This isn't actually a change to the engine, it's just a modification of the spider "stateset" to make proper use of an existing feature: key buffering.
As an example, before this change, if you pressed backwards+jump, you would turn around but not jump -- unless you held the jump key down until your spider was finished turning around.
Now, you can tap back+jump, and your spider will turn around, then jump.

It's simple, but the game feels much more responsive now.

(Oh yeah... and this was added in lieu of running, see previous post. I did manage to add a running animation, but it felt weird. Ultimately I just tweaked the tutorial's map to give you more choices, so instead of just holding right, you can time some jumps to move through it faster. And I added a secret shortcut...)
« Last Edit: January 16, 2022, 01:52:36 PM by bayersglassey » Logged
bayersglassey
Level 0
***



View Profile
« Reply #24 on: January 17, 2022, 10:18:42 PM »


Abilities

From the beginning, I wanted to avoid this game being "just a Metroidvania", where everything is organized around leading you to pick-ups which give you abilities which enable you to backtrack and blah blah blah.
But I still wanted to have different abilities, just so I could play with the engine more. So I implemented them as different "types" of spider:



Their abilities are:
  • Regular spider: nothing special
  • Roller spider: can roll around sharp edges while crouching
  • Aimer spider: can aim diagonally upwards (and thereby spit & jump diagonally)
  • Flier spider: can fly at will
  • Spikey spider: while crouching, extrudes spikes which make you invincible to "damage" from enemies
  • Eyeball spider: can close its eye (not really an ability... eyeball spiders aren't meant to be playable, they're meant to be used as NPCs)
  • Coin beast / purple person: nothing special, not a spider


...you were (and are) able to change between the different spider types by entering "doors" (glowing blue things).
However, this is strictly less interesting than being able to mix and match the various abilities.
So, what with the engine changes over the past few months (including the beefed-up scripting language), I switched the checks for whether you "have" a given ability from "is my stateset this one" to "is this scripting language variable true". With multiple scripting variables, that lets us mix and match the various abilities.

You can see this at work in the save file format below. The stateset is "anim/spider.fus" (the regular spider), but the "is_aimerspider" and "is_spikeyspider" variables are also set to T (true):



version: 0
game:
    vars:
players:
    :
        keymap: 0
        spawn: 25 30 0 n "data/maps/demo/worldmap.fus" "anim/spider.fus" "step"
        body:
            vars:
                "is_rollerspider": F
                "is_aimerspider": T
                "is_spikeyspider": T
                "is_flierspider": F
                "is_birdspider": F
maps:
    "data/maps/tutorial/worldmap.fus":
        vars:
            "made_it_underneath": F
            "going_upwards": F
        submaps:
    "data/maps/demo/worldmap.fus":
        vars:
            "guide_passed_start": T
            "guide_passed_start2": T
            "eyespider_tunnels_ran_away_1": T
            "eyespider_vines_ran_away_1": T
            "eyespider_vines_ran_away_2": F
            "eyespider_vines_ran_away_3": F
            "eyespider_vines_ran_away_4": F
            "jungle_cage": F
            "vines3_door": F
            "spider_passed_vines": F
            "spider_passed_vines2": F
            "eyespider_dodecas_ran_away_1": T
            "map3_blocker": F
            "map3x_blocker": F
        submaps:
            "start":
                visited: t
            "start2":
                visited: t
            "start3":
                visited: t
            "vines":
                visited: t



...you can also see that the save file format is now "versioned", with a version of 0.
Next time I make breaking changes to the format, I'll bump it to version 1.
When you try to load a saved game, if its format is the wrong version, you now get a friendly message
to that effect, instead of the game crashing. O_o

...you can also see how the minimap is "populated" (and how that is saved): there are named "submaps" which have a "visited" property of "t" (true) or "f" (false).


Anyway, one issue with this approach (abilities controlled by variables instead of statesets) is that your appearance no longer tells you what abilities you have.
And in the case of the "spikey" spider, that's a particularly big issue, because your spikes are supposed to extrude when you crouch.
There might be a solution using a recently-added engine feature: labels (see below).


Labels

The graphics engine's concept of an "image" is called a "rendergraph" (see this post for gory details).
It's something which can be rendered at a particular position, and can be rotated and flipped, and can be animated (have multiple frames of animation, each representing a different image).
A rendergraph can't be customized or broken apart: the whole thing is either rendered or not.
So how can we have sprites which can be customized?..
For example, imagine a character who can wear different hats.
We need to use multiple rendergraphs to do this: for instance, we can use one rendergraph for the the character, and another rendergraph for the hat.
But rendergraphs are animated, and when the character's body moves, we presumably want the hat to stay on his head.
So this is where the concept of "labels" comes in: a label is a named point on a rendergraph, where other rendergraphs can be "attached".

So, the character's body's rendergraph can now be defined something like:


shapes:
    "character_head":
        labels:
            # This is a label called "hat" located at position (0 1 -1 0),
            # with a rotation of 2 (that is, 2*30 = 60 degrees) and not
            # flipped ("f" is for false)
            : "hat" (0 1 -1 0) 2 f
        prismels:
            # ...the prismels making up this rendergraph's image...

    "character_body":
        prismels:
            # ...the prismels making up this rendergraph's image...
        shapes:
            # We make use of the head's rendergraph, rendering its prismels
            # on top of our own, and inheriting its labels.
            : "character_head" (0 0 -3 2) 0 f

    "hat":
        prismels:
            # ...the prismels making up this rendergraph's image...


...each body (each sprite) keeps track of which rendergraphs are mapped to which labels.
So if our character is wearing a sombrero, then his body has stored a label-to-rendergraph mapping like: "hat" -> "sombrero".

The "label-to-rendergraph mapping" system is plugged into the scripting language, so all kinds of things are possible.
Currently, the spider's rendergraphs (there's one rendergraph for each animation) all have a "carrying" label (located on top of the spider's "nose"), and this is used to implement carryable items (such as eyeballs and "food", which is little green squares):


Logged
bayersglassey
Level 0
***



View Profile
« Reply #25 on: January 31, 2022, 12:04:22 AM »

Update

Oh man, lots of changes. Here is a list of stuff I'd like to write about:

  • Character customization with "labels"
  • Some new abilities
  • A plan for the overarching structure of the game
  • Theme underlying level design: Wilderness vs Civilization
  • Elements of level design: safe vs dangerous structures
  • Bought some of those wooden blocks to play with!

...let's see how far we get.



Character customization with "labels"

In the previous post, I mentioned a new engine feature, "labels", where basically I can label points in each animation where images can be attached at runtime.
And since that post, I have actually converted the spider's animations to consist entirely of labels.
That is, the animations consist of animated points where various body parts can be attached, and at runtime, depending on which abilities you have, different versions of those body parts are used.

This was quite easy to do, because all the animations are written by hand in this strange text format, and I largely just had to do a find-and-replace of "shapes" to "labels". Here's part of the git commit which achieved it:

     $PREFIX NS "step":
         animation: cycle 3
-        shapes:
-            : $PREFIX NS "head" (-1  0  3  1)  0 f  0 (0 1)
-            : $PREFIX NS "head" ( 0  0  3  1)  0 f  0 (1 1)
-            : $PREFIX NS "head" ( 0  1  3  1)  0 f  0 (2 1)
-            : $PREFIX NS "bleg"  (-1  1  1  1)  0 f
-            : $PREFIX NS "fleg"  ( 2  1  1  1)  6 t
+        labels:
+            : "label:head" (-1  0  3  1)  0 f  (0 1)
+            : "label:head" ( 0  0  3  1)  0 f  (1 1)
+            : "label:head" ( 0  1  3  1)  0 f  (2 1)
+            : "label:bleg"  (-1  1  1  1)  0 f
+            : "label:fleg"  ( 2  1  1  1)  6 t


...so the spider's images are now all empty (they have no prismels of their own), they just specify a bunch of points where other images can be glued on. And many of those images do the same thing: for instance, the head is composed of an eye, a nose, optional head spikes, and an optional head bump.

Accordingly, there is now some code which has to choose images for all these things, based on which abilities you have.
Specifically, there are a bunch of scripting language variables which are declared to represent labels, and a "proc" (procedure) which is called every time spider's labels should be updated (so, when you gain a new ability):

vars:
    # Labels which *don't* depend on "is_*spider" vars
    # (These labels are moved around to animate the spider)
    nosave label "label:head": $PREFIX NS "head"
    nosave label "label:crawl_head": $PREFIX NS "crawl_head"
    nosave label "label:sleep_head": $PREFIX NS "sleep_head"
    nosave label "label:fleg": $PREFIX NS "fleg"
    nosave label "label:bleg": $PREFIX NS "bleg"

    # Labels which *do* depend on "is_*spider" vars
    # (These labels are set by proc "update_vars", and are used
    # to customize the spider's appearance)
    nosave label "label:_head": null
    nosave label "label:eye": null
    nosave label "label:nose": null
    nosave label "label:toe": null
    nosave label "label:headbump": null
    nosave label "label:head_spikes": null
    nosave label "label:head_spikes_extended": null

proc toplevel onstatesetchange "update_vars":
    # Sets various vars which depend on the "is_*spider" vars.

    # Defaults:
    set myvar("label:_head"): $PREFIX NS "_head"
    set myvar("label:eye"): $PREFIX NS "eye"
    set myvar("label:nose"): $PREFIX NS "nose"
    set myvar("label:toe"): null
    set myvar("label:headbump"): null
    set myvar("label:head_spikes"): null
    set myvar("label:head_spikes_extended"): null

    # Overriding the defaults depending on what kind(s) of spider we are:
    if: expr: myvar("is_rollerspider")
    then:
        set myvar("label:_head"): $PREFIX NS "_head_roller"
    if: expr: myvar("is_aimerspider")
    then:
        set myvar("label:nose"): $PREFIX NS "nose_aimer"
        set myvar("label:headbump"): $PREFIX NS "headbump_aimer"
    if: expr: myvar("is_flierspider")
    then:
        set myvar("label:headbump"): $PREFIX NS "headbump_flier"
    if: expr: myvar("is_spikeyspider")
    then:
        set myvar("label:head_spikes"): $PREFIX NS "head_spikes"
        set myvar("label:head_spikes_extended"): $PREFIX NS "head_spikes_extended"
    if: expr: myvar("is_flipspider")
    then:
        set myvar("label:eye"): $PREFIX NS "eye_flip"
    if: expr: myvar("is_stickyspider")
    then:
        set myvar("label:toe"): $PREFIX NS "toe_sticky"

    # Set myvar("spit_anim")
    if: expr: myvar("is_spikeyspider")
    then: set myvar("spit_anim"): "anim/spikeyspit.fus"
    else: set myvar("spit_anim"): "anim/spit.fus"


...and, lo and behold, as I run through this test area touching the glowing blue things (each of which grants a different ability), my spider's appearance gets weirder and weirder:




...a big TODO: figure out some better designs for the appearance changes for each ability. O_o Right now it ends up looking like a mess.



Some new abilities

The current list of abilities is:
  • Roller spider: can roll around sharp corners
  • Aimer spider: can aim (and then spit and jump) diagonally upwards
  • Flipping spider: can flip under/around the ground while crouching
  • Sticky spider: can stand (but not crouch) on "dots" (graph vertices) directly, even when not connected by flat "ground" (graph edges)
  • Spikey spider: while crouching, extends protective spikes, preventing enemies from exploding you

The first four are pretty interesting. This game's "physics" (the rules which control your movement) are pretty unique, and all of these abilities modify those rules, giving you more and more freedom.

Here's a video showing how they work:





As an example of how the "sticky" ability was implemented... it was all done in the scripting language, by throwing more conditionals in there.
When not sticky, the spider can only stand on two vertices connected by an edge, like this:

 + - +

...however, when sticky, the spider can stand on two vertices without a connecting edge:

 +   +

...and here is how that gets used in practice:

    if:

        # If the "forward" arrow key (e.g. right if you're facing right) was down
        key: wasdown f

        # ...and there is solid ground in front of you
        # (the definition of which depends on whether you're sticky!)
        any:
            all:
                expr: myvar("is_stickyspider")
                coll: all yes
                    ;; ( )  +   +
            all:
                not: expr: myvar("is_stickyspider")
                coll: all yes
                    ;; ( )  + - +

        # ...and there is nothing blocking you from taking a step
        coll: all no
            ;;       \*/*
            ;;        + -
            ;;       /*\*
            ;; ( )

    then:

        # Take a step forwards
        move: 1 0
        goto delay: $GET_STR STATE_STEP



Part of the challenge will be how to teach someone playing the game how to use all these.
For that, I have a plan for the overarching structure of the game... to be described in the next post.
« Last Edit: January 31, 2022, 08:11:19 AM by bayersglassey » Logged
diegzumillo
Level 10
*****


This avatar is so old I still have a some hair


View Profile WWW
« Reply #26 on: January 31, 2022, 08:52:20 AM »

This is great! It feels like controlling molecular machines. Little RNA drones haha

I gave up on the demo in the part with the first moving enemy. While trying to figure out how to navigate forward it kept killing me and I eventually gave up.
Logged

bayersglassey
Level 0
***



View Profile
« Reply #27 on: February 06, 2022, 11:29:33 PM »

I gave up on the demo in the part with the first moving enemy. While trying to figure out how to navigate forward it kept killing me and I eventually gave up.

Ooh, that's good feedback. I tried to add a bunch of ways to get by it -- there are some safe places you can hide, or you can "spit" at the big rolling thing to make it turn around, etc.
But it's probably way too soon for all that, should probably have a bunch of rooms where examples of that kind of thing are shown, or something. Like, have computer-controlled spiders showing off examples of hiding, spitting, etc.

Thanks for taking the time to play it Smiley
Logged
diegzumillo
Level 10
*****


This avatar is so old I still have a some hair


View Profile WWW
« Reply #28 on: February 07, 2022, 04:33:14 AM »

I learned those moves there; I think that is a good place to teach those things. I guess what I'm sating is I would make navigating forward easier instead of removing the enemy. I was completely baffled by that platform configuration.
Logged

bayersglassey
Level 0
***



View Profile
« Reply #29 on: February 08, 2022, 09:22:36 AM »

Oh, interesting.
I would love to see which part of that area was the part that made you give it up, although I have a hunch I know where.
This fits in with some posts for this devlog I've been planning to write up, but long story short I've added some tiles to the map which you can pass through, but can be used to show where it's safe to jump.
Here is a test area showing them -- they're the grey lines:

Grey lines are not solid, they just show you safe jumps


I've added one to the spot I suspect gave the most trouble in the area you're talking about:


Does that look like it might have helped?
Logged
diegzumillo
Level 10
*****


This avatar is so old I still have a some hair


View Profile WWW
« Reply #30 on: February 08, 2022, 11:18:42 AM »

oh absolutely! that is exactly what I was trying to figure out. Although I'm not sure the lines don't soften the navigational puzzle aspect too much. I enjoyed finding out these invisible connections; but the enemy roaming around made that part tricky.
Logged

bayersglassey
Level 0
***



View Profile
« Reply #31 on: February 08, 2022, 12:52:30 PM »

Ok, nice.
Yeah, having the lines everywhere would be a bit crazy. The idea is to have a theme of "wilderness vs civilization", where some areas are "civilized": either designed so that all jumps are obvious and/or safe, or using visual clues like these lines to show you where to jump. (And the in-game explanation is something like, these are areas used by other spiders as well, so perhaps they built these guiderails for public use.)
...whereas other areas are "wilderness": there are lots of unsafe jumps, and it's often not clear how to get from one place to another.
For those areas, the player can use lots of different strategies to get around; e.g. just getting good at looking at the geometry and knowing where a jump will go, or using one's spit to see where a jump will go, or skipping a difficult area until one gets an ability from elsewhere which gives one greater freedom of movement.

I think, given that this area is encountered so early, and does have an enemy roaming about, it makes sense to throw the player a bone and show them at least one of the jumps...
Logged
Pages: 1 [2]
Print
Jump to:  

Theme orange-lt created by panic