Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411550 Posts in 69383 Topics- by 58442 Members - Latest Member: spitcards

May 03, 2024, 07:18:58 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsCommunityDevLogsSneaky (3D stealth game- source release)
Pages: [1] 2 3
Print
Author Topic: Sneaky (3D stealth game- source release)  (Read 11276 times)
Danmark
Level 7
**



View Profile
« on: January 15, 2012, 05:17:50 PM »

Sneaky (working title) is a simple, yet deep AI-centric stealth game. It emphasizes freedom of movement, strategy, and quick-thinking.





« Last Edit: February 19, 2015, 08:47:27 PM by Danmark » Logged
Mittens
Level 10
*****

.


View Profile WWW
« Reply #1 on: January 16, 2012, 03:29:32 AM »

I like where this looks like it's going, keep it up!
Logged

Franklin's Ghost
Level 10
*****



View Profile WWW
« Reply #2 on: January 16, 2012, 04:09:51 AM »

Looks interesting, can't wait to see where you take this.

What's going to be the players goal in the world? Where will they have to pick good paths to get to?
Logged

caffeine
Level 5
*****



View Profile
« Reply #3 on: January 16, 2012, 02:56:40 PM »

I love the fact that you can see the entire globe. This will look awesome with some nice lowpoly graphics haha.
Logged
Ashkin
Guest
« Reply #4 on: January 16, 2012, 03:12:24 PM »

Those screens are amazing.
Logged
Danmark
Level 7
**



View Profile
« Reply #5 on: January 17, 2012, 10:27:30 PM »

Sneaky (working title) is a simple, yet deep AI-centric stealth game. It emphasizes freedom of movement, strategy, and quick-thinking. There is no combat: it's purely a game of evasion. Influences include Jet Set Radio, Assassin's Creed, and the Metal Gear series.

Pictured is a randomly-generated test environment. Note the stereographic projection. The idea is to give the player a good view of (almost) the entire world at a glance, so they can easily pick a good path through to any location. Apart from that, the shots say little about visual style, because I'm putting off serious visual and audio work until the end (though I've an idea of where those aspects are headed).




It'll be free & open source. I'm using Unity Indie with C#. More on how I've implemented stuff, and the design as it stands later. A 20% completion figure must undoubtedly sounds ambitious considering how little is shown in those shots.

This is babby's first devlog, so please ask some questions if interested!
EDIT- moved this 1st post to 2nd post, tired of the ugly screenshot greeting my soon to be unpaying non-customers


Thanks for the encouraging words, guys!

What's going to be the players goal in the world? Where will they have to pick good paths to get to?

Abstractly, to complete a level the player will need to reach some number of locations, in any order they choose, within a certain time limit. As for what they must do at them thematically, it's undecided. Most likely collect objects. In any case, the locations will be clearly visible everywhere, via a column taller than the tallest building being projected upwards from each one.

I'm also thinking the player's position might be momentarily revealed upon reaching a location, so that evading enemies when there's lots of pressure is an integral part of the game, not just something players bring upon themselves by screwing up stealth.

The locations to be reached might be randomly placed, and initial enemy positions are certain to be. I don't want there to be much of a metagame to strategize in. Players must stay on their toes.






Pictured is an example of what's stored in the precomputed visibility data, in this case from the tile the player's on (a vertical tile in the second shot).

I need precomputed vis because the AI needs to reason about where to go, and their goal is to reach the player. To reach him, they need to first see him, so visibility information is crucial. Furthermore, it's utterly impossible to compute on-the-fly, because the NPCs need to make tens of thousands of visibility queries per second.

First some background. A map is defined by a 64x64 heightmap of integers. You might've guessed from the screenshots that the environments are urban. For my purposes, I've defined the environment to consist of tiles, both horizontal and vertical. There are exactly 64x64 ground tiles (the ground & roofs of buildings). A wall tile exists wherever there's a difference in height between two adjacent tiles in the heightmap: one wall tile per unit in the difference. The number of wall tiles varies depending on the map. Whether horizontal or vertical, all tiles have the same dimensions.

More background. It's (thankfully) not visible from the shots in the first post, but the world has a spherical topology: the left edge of the world is connected to the right, and the upper to the lower. Keep moving in one direction, and you'll end up back where you began. In fact, one of the edges is somewhere near the player in those shots (not sure where). Note that "edge" is kind of misleading, because there are no edges in terms of gameplay, which is the point. It's just necessary to consider the edges for implementation purposes. In fact I just thought of a way to demonstrate the sphereness. Please click:


That's just the world as viewed from an orthographic camera top-down, tiled twice. It tiles infinitely. The shading is due to my fakeass precomputed AO (a story for another day).

Now, the visibility precalculation must answer the question which tiles are fully visible from which tiles?. ("fully visible" means "an enemy can see from any point on tile a to all points on tile b"). To do this, it

1. Considers each tile in turn.
2. Considers tiles that might be visible from that 1.
3. Tests visibility from the tile given by 1 to each tile in 2.

Trouble is it's slow. Takes ~20 seconds per map on my Core i5 750. Not too surprising: with building height limited to 9 tiles, there are up to ~80,000 tiles. At the moment, there's still some room for optimization in 2 and (to a lesser extent) 3, while quite a bit is filled already. The whole thing's pretty easy to parallelize, because it can happen from 1, with no sharing of mutable data between threads. Not gonna go there unless I get desperate though.

Optimizations of 2 so far include considering each wall from the roof to the ground in that order. If a lower building is blocking my view of much of a taller one, there's a point above which I can see all of the taller building, and below which I can see none of it. Another optimization is considering only the tiles in front and to the sides. I can't very well see back through the wall behind me. Together, possibly in conjunction with things I don't recall, these doubled performance.

3 is implemented by raycasts. Originally I'd thought about doing something more sophisticated, but due in part to the "fully visible" requirement mentioned above, it got hideously complicated very quickly. Also, looking at the results of this comparative roguelike FOV algorithm study, the performance of techniques other than simple raycasting isn't very impressive.

To start with, I used Unity's own raycast function. It worked for the case where a ray starts & ends inside the logical world boundaries. To make it account for the world's topology, I needed to rearrange the chunks making up the world many times throughout visibility precalculation.

Yet more background. The world consists of 8x8 chunks of 8x8 ground tiles each. Each chunk is a collider and a mesh. This is necessary because of the vertex limit per mesh, and so that the player can see across the world. Basically, the player is always near the center of the world, and when they get far enough from it, a new world center is selected, and everything's invisibly rearranged to account for that (Dark City anyone?), as though the world is a giant omnidirectional treadmill. Unbelievably, this actually works now, for both the world chunks, and for objects at arbitrary positions.

Doing this rearranging as necessary for vis precalc didn't immediately work. Rather than trying to figure out why, it was expedient to just write my own heightmap raycast algorithm, because I'd wanted some effects showing where the enemies can see anyway (which also must account for the world's topology), and because any solution would've complicated the rest of the game. Was tricky getting it working perfectly, but the results are worth it. No more complexity needed for vis precalc, and the performance thereof doubled again (Unity's raycast is general-purpose; I had much domain knowledge to use).

Sadly, the quadrupling of performance is what got me to 20 seconds.

Being that this is precalculation, storage and retrieval are important considerations. Visibility is stored as a hash map from each tile to a unique list of tiles. All lists of tiles are stored densely in a big list (implemented as an array). When serialized to disk, it all comes to about 1.5 MB per map. One interesting thing here is that info about entire walls is stored as a start (highest tile visible on wall) and a count (total no. tiles visible on wall), cutting down on the necessary number of entries in the big list. Another is that the all info about a ground tile & its associated walls (x pos, y pos, wall start, wall end, ground visible) is stored in 8 bytes, and it's only stored if something's visible there. Suffice to say, the big list isn't getting more dense/less big anytime soon.

That concludes this magnificently verbose entry. Please give me your feedback, both on the game, and on the devlog so far. Next time I'm going to ramble on about controls & character controllers. There'll be a video! And I promise it won't be as lengthy!
« Last Edit: August 31, 2012, 12:21:25 AM by Veracity » Logged
Danmark
Level 7
**



View Profile
« Reply #6 on: February 04, 2012, 10:46:20 PM »



's a video of the movement in Sneaky.


Everything performed therein is done with 5 keys: WSAD to move, & the space bar to jump. I want control to be simple and intuitive. To climb up on a wall, keep moving towards it (or away to climb down). To roll around an edge, keep moving towards the edge. To travel horizontally along a wall, just move in the appropriate direction. All of these controls can be simultaneously mixed as well. Jumping is only a small hop, but it makes a big difference. It can be performed at any time the ball is in contact with a building.

One unfortunate trend in AAA games is animation controlling physics. For me, this instantly kills suspension of disbelief, every time. In Sneaky, animation is purely for visual feedback. While it's not the emphasis of the game, dexterity is necessary to traverse the world as quickly as possible. And dexterity is always relevant, because there's no waiting for animations to finish: you can move all the time.

The reason for the climbing and cornering abilities is that I thought an interesting idea is a stealth game where you can move on the surface of a 3D object, as opposed to just the ground. This is one thing the Assassin's Creed series does, albeit not in a very thorough or fun way.

Your enemies will have the same abilities, sans jumping. So the idea is to avoid their sight while making good time through the world.

Questions? Comments?

I'll write some words on the technical side if anyone's interesting. The tl;dr version is that it's the most hellishly difficult thing I've ever implemented. Easy to get running, nigh-impossible to make robust.
Logged
Franklin's Ghost
Level 10
*****



View Profile WWW
« Reply #7 on: February 04, 2012, 10:56:11 PM »

That video is awesome, the distortion of perspective is so trippy and hypnotic.

Looking really nice and like the climbing. Think it's something that's ignored lots of times in games where you are stuck on a level playing field. Adds another element of gameplay.

Also like your technical posts because I'm not very technical (but would like to be) so helps me see how other people work.

Could see a small Spiderman game being made with this time of gameplay  Smiley
Logged

JackMenhorn
Level 2
**


Sound Designer


View Profile WWW
« Reply #8 on: February 05, 2012, 05:35:20 AM »

Love where this is going.
Logged

Sound Designer<br />www.jackmenhorn.com

Nova-111 OST: https://jackmenhorn.bandcamp.com/album/nova-111
Danmark
Level 7
**



View Profile
« Reply #9 on: February 12, 2012, 04:16:07 PM »

Thanks for the comments.

Could see a small Spiderman game being made with this time of gameplay  Smiley

Brings to mind Spiderman 2, where you can crawl on walls & around edges. Same for Skulks in Natural Selection, and, hence the creatures' name, such movement is used for stealth in that game.

These games might be influences I hadn't thought of. The only difference here is you can traverse edges at full speed. In both those games, just traversing the world is joyous, and it's something I think it important for mine.
Logged
Danmark
Level 7
**



View Profile
« Reply #10 on: February 20, 2012, 03:09:00 AM »

Sorry for the lack of updates. Between starting another project, analysis paralysis regarding AI in Sneaky, and combating addiction, I've made little progress. More substantial post to follow tomorrow.


Just made the stereographic shader actually stereographic. Visual results pictured. Back around the time I wrote the shader (my first), I realized it wasn't really stereographic, because it just normalized vertices and projected them up to the viewport. But it looked good.

When I tested the game with an NPC rolling around, he appeared all squashed vertically. I realized this was due to a limitation in my "stereographic" shader, and moved to fix it, without remembering why it wasn't really stereographic. Figured out I needed to properly project the unit sphere (onto which all vertices in the world are mapped) onto the viewport, through the top of the unit sphere. So I did it, pic related.

Unfortunately, buildings looked better before, and it was easier to get a sense of the shape of the world. It's all a trade-off.

I promise I'll type out actual English tomorrow as well.
Logged
Danmark
Level 7
**



View Profile
« Reply #11 on: February 25, 2012, 10:21:46 AM »

Better late than never? Clicky:


Now the enemies have those search beams drunk rotating around them all the time. The intention is give a rough idea of where they can see, and also to make enemies who are distant or behind buildings visible. A pleasant side-effect is a menacing appearance. Later on, I think I'll make the beams converge close to the player when he's nearly within sight, spatial perception being tricky with the fixed top-down stereographic view.

Had lots of trouble getting those beams working. The rotation you see on the player, enemies, and beams is my own. This was necessary because I'm using a "surface shader" in Unity. It seems that when you do vertex manipulation, it's only in object space, and Unity then applies its own rotation on top of that, thus producing incorrect results for objects at anything other than identity/no rotation.

So instead, a quaternion is stored for every rotatable object, and the stereographic vertex shader has parameters for up and forward vectors (it infers the right one via a cross product), from which it makes a rotation matrix. Each vertex is rotated by this matrix. At some point I might make the shader parameter a quaternion & do the appropriate math in the shader, which should be faster, but with only a few hundred objects tops, it probably wouldn't make much difference. Anyway, it took many hours to find out that my object space vertex position with rotation matrix multiplication was backwards.

I added fog to help hide the massive pop-in of buildings that occurs due to the world chunks being rearranged (as discussed in the second post), because that problem was severely exacerbated when I made the stereographic shader "proper". Makes the whole world more moody. Testing various fog algorithms, I decided on exponential squared fog, because I don't want areas near to the player to be affected so much. Then, I made it exponential cubed, pushing the fog even further away. Exponential hypercubed or whatever is also an option, pictured below (clicky). What do you guys think? It's exp-cubed in the video.


Next task is the move propagation system, for handling precomputed knowledge about how the player can move through the environment. Unsurprisingly, it's turning out to be hideously complicated, due to the player's jumping/falling abilities. Should make for another lengthy technical post.
« Last Edit: February 26, 2012, 03:45:09 PM by Veracity » Logged
Ashkin
Guest
« Reply #12 on: February 25, 2012, 01:12:50 PM »

The technical stuff is too difficult for me to grasp, but that sure looks pretty.
Logged
:^)
Level 10
*****


wat a hell


View Profile WWW
« Reply #13 on: February 25, 2012, 02:00:41 PM »

my eyes hurt. but i like it?
Logged
Franklin's Ghost
Level 10
*****



View Profile WWW
« Reply #14 on: February 26, 2012, 03:36:19 AM »

Really like your technical posts (even if I don't understand most of them  Smiley ) but just a great way to see how you work and learn new things. Like the enemies search beams and think it'll work even better when you get the convergence on the player when close. Also the distance fog is a great way to handle the popping in and out of buildings.
Logged

Danmark
Level 7
**



View Profile
« Reply #15 on: February 26, 2012, 03:53:42 PM »

Thanks guys.

Due to the comments, I edited the second and third paragraphs of my last post for clarity. It really didn't make sense before, even if you were familiar with matrices.
Logged
Danmark
Level 7
**



View Profile
« Reply #16 on: March 15, 2012, 01:17:34 AM »

So I've been working on the second subsystem AI depends on, the first being visibility. This one determines where the player can possibly be, and how long he could've been at each position (tile). I'm calling this the "propagation" system, because the potential positions comprise a field that propagates through the world according to the movement rules governing the player. It has a static (precomputed per environment) and dynamic portion. The static portion is described below.

Forgive the goofy visualization, lack of rotation, and flatness. Darker green tiles are ones reached further in the future.


The propagation system, like the visibility one, requires lots of precomputation. In this case, the necessary data says which tiles are directly accessible via which others, and how long the trip from each tile to each such neighbor takes. Directly accessible is defined as "reachable by moving or jumping without touching any tiles other than the source and destination tiles".

Recall that my maps are defined as heightfields. What I do is, for each tile to each potential neighbor (tile within a certain range), cast a ray in two dimensions along the ground plane from the center of the source tile, to the center of the destination tile. The ray represents the motion of the player along the ground plane. At each raycaster iteration, the hypothetical player is above a new tile.

I stressed the 2D part, because the up axis is dealt with in a different way. Using the equations of motion, I work out the actual height of the imaginary player upon each raycaster iteration, to see if he prematurely hit into a wall or ceiling. If he did, the destination tile is unreachable. The arc of the player's jump/fall is thus accounted for:

Code:
//from SUVAT [2]
float height = gravity*time*time*0.5f + jumpSpeed*time + heightOriginal;

If the ray reached the destination, it's added as a reachable tile from the source tile, along with the first reachable wall tile per side (NESW) if present. It would be easy to add every reachable wall tile, but storage/retrieval costs would explode for little benefit, so I won't bother unless it becomes necessary. Anyway, the total time it takes to reach a tile is also calculated with equations of motion.

Of course there were lots of gotchas. For instance, 4 neighbors (NESW) are added no matter what, because they're always reachable. To avoid duplicate entries with those and others (i.e. tile A connects to tile B at 2 different times), I start the cast at the first reached tile, rather than the source tile. Might come up with a better hack later.

As for storage, it's similar to the visibility system. A big list of all lists is stored. A dictionary maps tile coordinates to index/count pairs defining lists of reachable tiles within the big list. Each entry in a reachable tiles list contains info necessary to reconstruct that tile's coordinates (squashed down & relative to reached-from tile), as well as a time in milliseconds representing how long it takes to get to that tile. Each reachable tiles list is sorted by time ascending when its content is complete. This is so the dynamic portion of the propagation system can access tiles in proper order, wasting no time. When serialized to disk, it comes to ~3 MB per map.

Expect a public alpha on the 30th.
Logged
Ashkin
Guest
« Reply #17 on: March 15, 2012, 10:22:26 AM »

Are you planning on sticking with the clean white visuals, or will you be adding textures and adornments?
Logged
Danmark
Level 7
**



View Profile
« Reply #18 on: March 15, 2012, 01:00:21 PM »

^ Textures for sure. Adornments, not likely. There's no point in little objects that have to be navigated around, and even less in visible props that don't collide.

Thinking of basing the style on Shibam in Yemen:

Logged
Danmark
Level 7
**



View Profile
« Reply #19 on: April 01, 2012, 08:20:13 AM »

This isn't at a more advanced stage than what was shown on the first video, but here's a demo (Windows). Wanted to post it on the 30th, when TIGSource was down. Please report all issues you have.

On the plus side, the dynamic part of the propagation system is basically complete, and I'll write a lengthy technical post about it soonish. Hopefully. Next major feature: AI itself.
Logged
Pages: [1] 2 3
Print
Jump to:  

Theme orange-lt created by panic