Announcement

Collapse
No announcement yet.

eternal apex // ambient cyberpunk megastructure endless rider

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

    [GAME] eternal apex // ambient cyberpunk megastructure endless rider

    click for youtube video:
    (audio is important, and try to watch in 4k fullscreen
    even if you have a 1080p monitor -- the 1080p and lower video is chunky)



    eternal apex //
    an ambient (no goals, just cruising), high speed, futuristic tunnel racer prototype



    An impromptu game design challenge over a few late nights recently to better wrap my head around:

    - World origin shifting to seamlessly offset player and world geometry every 100k units in direction of player movement indefinitely

    - World position offset in the materials for road, walls, and ceiling (including emissive light bar) to curve tunnel into the distance; updated offset target over time depending on player velocity to gradually change curve; used same formula in blueprint to update position of ceiling point lights to match emissive light bar mesh

    - Single instanced static mesh for all towers and overpasses, procedurally sized and positioned at runtime

    - Tunnel segments procedurally placed at runtime randomly chosen from preset patterns (fully enclosed tunnel, open-sided tunnel, open-roofed tunnel, arches, etc)

    - 24 fps gameplay: this topic is contentious, but I'm a cinemaphile and love the 24fps cinematic "look" -- however most games feel very jerky and unresponsive at such a low framerate, so I designed motion and input from the ground up to look and feel smooth and natural at this more film-like framerate (although it's still possible to play at 60fps or higher with a toggle)



    Sadly my modeling and texturing skills are lacking, so for the sake of rapid prototyping:

    - Motorcycle and all level geometry were made in blueprints from stock spheres and cubes

    - All textures and materials are very basic, using stock concrete texture and simple road stripes overlaid

    - Headlight and taillight are just point lights using in-engine IES profiles







    Desktop looks and feels very good, but I'm still working on mobile support for the learning experience:

    - even on my "high end" mobile device (Android), dynamic lighting support is very limited, so I'm currently attempting to find a way to "paint" the headlight and taillight beams into the road/wall/ceiling materials

    - postprocessing is very limited, so motion blur, bloom, depth of field, etc are worse or nonexistent

    However, performance is good, and touch/tilt/cam rotation controls feel very good.


    More to come...
    Last edited by acatalept; 06-27-2018, 01:30 PM.

    SINGMETOSLEEP / PARASOMNIA / DARKDRIFT / ETERNAL APEX / PRETTY ABRASIVE MUSIC / TWITTER @ACATALEPT

    #2
    Really digging the atmosphere of this! Felt really good once the smaller structures whizzed by and you got a real sense on how fast you're going~
    -cisco

    Comment


      #3
      Beautiful - reminds me a lot of the demoscene community's work.

      Comment


        #4
        How I got World Origin Shifting to work


        I have a BP_Pawn blueprint which contains the bike and player logic, and a BP_WorldSpawn blueprint which is the parent of all the world geometry (road, walls, towers, overpasses), and manages spawning and reusing world geometry.



        1. In BP_Pawn, on Tick, check to see if we've passed a predefined World Shift threshold (I set this variable to 100000 for testing, but this should be set to less than where you start seeing floating-point precision errors). Note that my game's player moves along the X vector in world space -- make sure you change this if your game's orientation is different. Also save the BP_Pawn actor's current location as we'll need this later:





        2. In BP_Pawn, set the new World Origin Location to the current world origin location (this will start at 0,0,0 and change each time we do a world origin shift) *plus* current BP_Pawn actor location. Note that you must truncate floats to ints, and manually break apart and add the Int Vector x,y,z components (there's no built-in blueprint function for adding Int Vectors). I've also flagged a boolean WorldOriginShiftInProgress variable to prevent certain updates elsewhere in my code -- this may be applicable in your case if you get 1-frame glitches (geometry moving/freezing unexpectedly) during world origin shifting.





        3. Finally in BP_Pawn, call a world shift update event we've created in BP_WorldSpawn (explained below):





        4. In BP_WorldSpawn, handle the WorldShift custom event: move the BP_WorldSpawn actor (which is the parent of all world geometry) *forward* to compensate for having just moved everything backward as a result of the world origin shift location change. Note that I'm using the exact same truncated vector value I saved previously in BP_Pawn, in order for everything to line up seamlessly. (NOTE: ignore the superfluous BreakVector feeding directly back into a MakeVector in this screenshot, it's harmless but not necessary -- I was originally tweaking the values while trying to experiment with some glitches I was having earlier in development)





        5. Get the opposite of the direction we're moving the BP_WorldSpawn actor (along the X vector in world space in the case of this game, but this will depend on your game's orientation):





        6. Finally, move all child components (this is all the world geometry: road segments, walls, towers, overpasses) in the opposite direction that we just moved the BP_WorldSpawn parent actor that contains them, by adding the same negative world offset to each. Some of these are just mesh scene components (which I've stored in arrays as they were spawned), and some are Instanced Static Mesh components which contain collections of instances (all parented to the ISM component). Note that I spawned all level geometry at the beginning of the game, and simply reuse the same pieces over and over by showing/hiding/moving them, in order the save the processing and garbage collection overhead of spawning and destroying components.





        In summary, this all seems overly complex, but basically:

        1. Increment the World Origin Location by a threshold we define (whatever amount is safely less than where we start seeing floating point math errors). This is a hidden Large Int (int64) value used by the engine as a location offset for very large worlds: each time we change it, everything in the game seamlessly moves by that amount. It all appears to be right where it was previously *relative to everything else* in the world, but under the hood the absolute position has changed.

        2. Move any applicable actors to compensate, *if needed*. An "endless runner" is a rather different case than say a large open world exploration game: In this case, I have an invisible world geometry parent actor (BP_WorldSpawn) which will gradually get left far behind. So I want to keep moving it on each world origin location change to keep up with the player actor, no matter how far the player gets from the original (hidden) World Origin Location 0,0,0 we started at. However, since we're moving the parent BP_WorldSpawn actor, we then need to move all the child geometry components within it *backward* (the opposite of the direction we just moved the BP_WorldSpawn actor forward) so that everything *appears* to be in the same place.

        This results in everything calculating correctly, moving seamlessly, correct physics, no graphics glitches or memory leaking, even after many hours of letting it run, and thousands of world origin shifts.

        Hope this helps!
        Last edited by acatalept; 08-18-2019, 12:01 PM.

        SINGMETOSLEEP / PARASOMNIA / DARKDRIFT / ETERNAL APEX / PRETTY ABRASIVE MUSIC / TWITTER @ACATALEPT

        Comment

        Working...
        X