First-Person Rogue-lite Project

Hello and welcome to the Blender First-Person Roguelite project, loosely named “Blogue”.

This is an attempt to mix the action and engagement of a First-Person Shooter with the depth and exploration elements of a procedurally-generated RPG (aka the Roguelike).
An attempt is also being made to emulate the graphical styles of the mid-90s SVGA games. The retro angle is something I seem to be unable to avoid anymore :wink:

A playable demo is now available here:
https://github.com/YeOldeDM/blogue

(the Download Zip button is in the lower right corner, for the uninformed. I know it took me a while to find that thing hidden down there…)

This will be updated on a regular basis, so make sure to grab a new copy if you want the latest updates.

Current Status: Tech Demo
First Alpha Due Date: Oct 8th

I am currently accepting any and all forms of playtester feedback! Comments, LPs, LPs with comments, whatever you wish to contribute. Your input really matters!

=============================
(original post):

My previous project (which has yet to be to a show-able state) is quickly proving to be way more than I can chew on my own. My recent BGMC entry was sort of a bust. So, I return to an old project.

This was one of my first “I wish I could do this in Blender” ideas; a first-person action/adventure/(survival?) game using prodedurally-generated dungeons and other rogue-like elements.

That was about a year ago, and now, with all that I’ve learned, I feel much more confident in taking this thing on once again.

I’ve got a solid (if limited) FPS rig put together, and the foundation of a random dungeon generator up and running. I have been working on some tricks regarding 2.5D sprites, and I plan on using those for most of the props in the game, both for performance and design reasons. An old-schoolie 90s FPS look (with a modern touch-up) is what I’m going for.

All textures are made from images from cgtextures.com. Normal/specular/etc maps were generated from source images using GIMP and Blender.

Ultima Underworld, without the crap interface/controls? :yes:

Sounds cool. So the style will be kinda like Doom, amiright?

Really cool, love the style.

Great idea!
I’ve got some monsters I can donate if you’d like…
The RPG tpye dungeon crawl is something I keep coming back to again and again, but I never seem to get anything finished.
I think if you keep it simple like this you can get a working prototype in a couple of weeks.

I think, like doom it might be a good idea to lock the up/down axis of the mouselook otherwise it can make sprites look strange once you get up close.

Good luck with this, I’d really like to see how it turns out. :smiley:

So far, I’ve been trying to use this as a guideline to building this thing up. I put myself through this tutorial a few times while first diving into python, so I know the structure of it well.
Of course, it’s going to quickly deviate into some other kind of monster, as the architecture of the two environments vary so greatly. But many of the principles of the development process seem they can cover common ground.

This will certainly not be a turn-based game. Many of the RPG elements may be replaced with more traditional shoot-em-up elements. At least for now.

I can see how generic FPS action mixed with random (generic) level generation could make for stale game play, but it is at least a reasonable goal to work toward.

@smoking: I would love to see/probably use your donations. I have no vision of the art direction for this, anything at this point could be a viable asset.

I didn’t lock the up/down movement of the mouselook (that feels weird), but I have restricted it to about 45 deg. in both directions. You get some room to look up and down but not so much that it’s going to deform the billboard sprites too much. Everything is going to be happening on a level plane, so looking up and down has no real purpose, but feels like something that should be there anyway.

Next Up: Barrels will turn into Baddies, hopefully some global prop/entity management, and maybe a mini-map in the HUD?

Are you planing to do characters in 3D or sprites?

Another video update!

Updates:
-New textures. These are way too ‘clean’ at the moment, but can be grunged up in the future. I also scaled the player/monsters down quite a bit. Maybe too much…
-Minimap: Shows the world around you, to help you maintain your bearings. No Fog of War or any of that, but I don’t think it’s really needed here.
-Some very basic monsters with some very basic AI. (graphics for these are ripped from Hexen, and are place-holders)
-Basic combat. The player can execute an Attack(), which is generic for any creature who attacks. Targets are knocked back (which is very glitchy ATM), and feedback is provided to the python console to confirm the attacker/defender/amount of damage/etc.
-Building up the framework for a generic item/entity ‘class composition’ system. People making new monsters/items/etc should have to do little more than create the model(s), and define a few properties on the model to tie it to its in-game Entity logic.

NEXT:
-Make the monsters hostile, make damage real (ie monsters/player can Die)
-End game conditions for the player (starting on perma-death)
-Top-level menu for starting new games/generating new dungeons (and eventually resuming saved games)

Nice, but I really enjoyed the dark style of the dungeon in the last video. Anyway is good to have variety.

What kind of AI are you thinking of doing?
I think a kind of wandering AI works best for games like this, where the enemy doesn’t always take the closest route to the player, but kind of walks around more…
I used one before where the bad guys wandered around a set of waypoints, trying not to visit places they’ve already been or that are already occupied by other monsters. If they see the player they choose the waypoint closest to the player, but again trying not to double back. This makes the monsters more interesting IMHO because they seem to be doing other things, not just only focused on attacking the player. You get to see them from different angles too, instead of always having them walking towards you.

You could do a really smart A*pathfinding AI where the monsters wait in groups to attack or try to get behind the player, but really the dumb AI actually seems more realistic and in the end more fun as the player actually has a chance to try and outwit the dumb monsters.

Also, what’s the overall tactical goal in the game? Pure hack and slash games can get a bit stale; fight, heal, fight, you know the formula. In that case there’s not much for the player to do “Doh, I fought when I should have healed!” so you need something for the player to do to increase their chance of winning through skill rather than luck. Some games have ranged weapons, but with limited ammo, so you have to choose where and when to use them. Magic can serve the same purpose. Also the ability to recover and use traps against your foes can really give a game some fun tactical choices. How about stealth? Sneaking up on a sleeping monster could be fun. Another idea is what Haidme used in Krum, the shield block. Players or enemies blocking or parrying attacks can make combat more than just button mashing, it requires quite precise timing to launch a successful attack.

Anyway, it’s looking great. Can’t wait to play it!

This game looks pretty good!:slight_smile:

In trying to figure out how to handle animation, I have written this Sprite Wrapper.
This should be universal and super-flexible.
Have your animation frames set up as meshes in an inactive layer, with appropriate names (sort of outlined in the script…better documentation will be needed for general human consumption). Have a python script call an instance of Sprite, passing a master mesh (could just be a plain plane) as the first argument.

With a couple properties defined on the master Sprite mesh, the wrapper can smoothly and properly animate both ‘one-shot’ animations and animation loops. You set the number of frames in your cycle, as well as the length of the cycle in logic ticks (or whatever you call it…60 ticks = 1 second?). This, along with the Name of the sprite, and optional ‘action’ and ‘direction’ (which would require the special direction script in my game to work here) parameters, it will dutifully animate any sprite, in any action, from any angle. Sprite textures do not have to be ‘gridded out’ (which would be the case for using animated textues), you can have any number of frames playing at any framerate, and any of this can be altered on-the-fly.
The Sprite class keeps its current frame as an attribute, along with a ‘hit_frame’ value which will trigger an event. In the case of my game so far, the player’s weapon animation is triggered by the player (via left mouse click). The actual attack logic is triggered by the weapon’s animation reaching the appropriate frame; so you have a proper delay between triggering an attack and actually landing that attack.

(it still needs work, but here is what I have so far)


'''
Sprite objects should have the following properties defined:
(int) "frames": the number of frames in the animation cycle
(int) "rate": The number of real frames the animation lasts (60=1 sec. at 60fps)
(int) "hit_frame": (optional) the frame in which the Sprite triggers an event (like a weapon/monster attack)
'''




class Sprite:
	def __init__(self, own, Name, loop=False):
		self.own = own
		self.Name = Name
		self.loop = loop	#if true, animation runs on a loop. Otherwise, it runs as a one-shot
		self.timer = 0
		self.current_frame = 0
		self.active = False
		
		self.direction = None	#If not None, add a direction to the frame
		self.action = None	#if not None, action is added to mesh string to provide multiple animation cycles. 'walk', 'attack', 'death', 'leg-hump', etc
		#Naming conventions for animation frame meshes is 'N_A_D_F' where:
			#N = Name of the object ("Goblin")
			#A = Name of action(if present) ("Attack")
			#D = Direction facing of the sprite (-3 to 4)
			#F = The frame number (4), first frame must be 0.
			#That mesh would be named "Goblin_Attack_-1_4"
			#Only the first and last values are required. A and D are optional.
	
	#start an animation
	def start(self):
		if not self.active:
			self.active = True
	
	#(experimental) stop an animation
	def stop(self):
		if self.active:
			self.active = False
			self.timer = 0
			self.current_frame = 0
	
	#(experimental) pause an animation
	def pause(self):
		if self.active:
			self.active = False
	
	#sets the mesh based on the NADF formula		
	def set_mesh(self,frame=None):
		N = self.Name + '_'
		A = ''
		D = ''
		F = str(self.current_frame)
		if frame != None:
			F = str(frame)
			
		if self.action:
			A = self.action + '_'
		if self.direction:
			D = self.direction + '_'
		self.own.replaceMesh(N+A+D+F)
	
	
	#the frame-by-frame management of animation			
	def animate(self):
		if self.active:
			self.timer += 1
			if self.timer >= self.own['rate']:
				if not self.loop:
					self.stop()
					self.set_mesh()
				
			else:
				period = self.timer / self.own['rate'] * 10
				self.current_frame = min(self.own['frames']-1, round(period * (self.own['frames']/10)))
				self.set_mesh()

And a small example of how it is used, here is the code snippet from my control script that handles the player attack:
((own[‘ent’].hands is the Sprite() instance for the player’s FOV weapon object))


	mouse = logic.mouse
	LEFT_CLICK = logic.KX_INPUT_JUST_ACTIVATED == mouse.events[events.LEFTMOUSE]
	H = own['ent'].hands
	if LEFT_CLICK:
		if H.timer <= 0:
			H.start()
	H.animate()
	if H.current_frame == H.own['hit_frame'] and not own['STRIKE']:
		own['ent'].fighter.attack()
		own['STRIKE'] = True
	if not H.active:
		own['STRIKE'] = False

The player has a STRIKE bool property, which ensures the attack will only trigger the instant the two values become equal (otherwise, you end up doing like four attacks per click). This will probably be worked into the wrapper, as kind of ‘pulse’ control will probably be a common need.

Monsters are now taking damage when they’re hit with the player’s weapon, and enter a ‘dead’ state when they run out of hitpoints. A little more work and the monsters will be able to fight back (their attack logic is going to have to be a bit different than the player’s) and eventually kill the player, as well as turn into corpses when they die. Blood spray particles, decals, gibs, and all that good gory stuff is going to be in there at some point as well.

I tweaked the AI a little, but haven’t put much work into it lately. Now, monsters will stop moving if an entity is bocking their way. This keeps mobs of baddies from bum-rushing you into/through the walls, at least. Now, they are very polite and wait their turn to be slaughtered :wink:

Renaming objects is an activity that can take up far too much of your time if you’re not careful.
Blender has to be able to find each frame of your animation, and that means either using a sprite sheet (to find it by location on a UV) or individually unwrapping and naming hundreds of single images.

Before you get started on that it’s best to do a few experiments on how you can automate the whole business using bpy and bmesh.
If you plan it out well you can save a lot of time indeed.

Here’s a very ugly example of a script for splitting up a sprite sheet:
sprite_maker.blend (603 KB)

It’s probably not directly useful to you, but I hope it shows how you can save a lot of time with the right setup.

(I don’t really like the regular blender API, there are three different ways of doing things, and often only one of those can do the thing you need to do, so you have to keep switching back and forth between the different methods and keeping the context correct just in case you have to switch back).

I was about to the point to start asking you about this very issue (you hint at it farther up the post). This is wonderful, just what I’m going to need! Thank you very much! Something like this is certainly going to be needed once (if) assets start being created on an industrial scale.

I am going to have to dedicate some time to getting familiar with bpy (I’ve managed to never touch it up to this point). It seems you can do some powerful things with it, as far as automating workflow.

(BTW Smoking, I’ve been borrowing your method for key/mouse input as well, and have that integrated into this. All that’s needed is to make some kind of options menu where the player can re-define the controls and save them up in the globalDict.

I will post a new video later today, after I get some time to record one.

The game does not look very exciting yet, but a lot of functionality has been added in!
Monsters will fight you, and will also go ahead and fight each other!

I think I’ve cracked down on an old issue I’ve been avoiding: monsters not correctly losing their line of sight to the player through walls (which is done via a rayCastTo() call). The reason for this, I believe, is the fact that most of the dungeon walls are being culled, and therefor are not receiving collisions! So a system will have to be put in place to check LOS via the system’s map grid, which I should be able to monkey out here easily enough. More grunt work, yay!

My entry for BGMC14 (robots of mars) has a scene with a custom controls setup, though it’s pretty ugly code because of rushing for inclusion in the game before the end of the challenge.

Occlusion culling is great in theory but you might be better off just having a fairly short camera clipping distance, then you can continue using raycast for AI navigation. Mist or darkness will cover up any uglyness.

And so I have. I have changed the occlusion cubes into invisible cubes, with collision and the proper property to detect them. LOS works great now, but performance drops on large maps, but I chalk that up mostly to my hardware. My camera distance is only 35 BU so that helps (one of the benefits of setting your game in a demandingly dark environment).

What I could do, is spawn in solid block colliders along the borders of the map walls (that is, a ‘wall’ tile which has at least one ‘open’ neighbor). That would reduce the number of objects being spawned in currently, I think. This, along with a similar ‘Big Plate’ objects acting as floor and ceiling…the dungeon meshes themselves can sit back and be no collision decoration.

I just hope things don’t get too laggy once more clutter props and objects are added to the environment. Or perhaps there’s a way to cull those objects like I was doing, but prevent just the walls/AI entities from being culled…

Having a small/medium/large/x-large setting for the map at game start will probably be a thing.
-Small: ~20x20 tiles
-Medium: ~40x40 tiles
-Large: ~60x60 tiles
-XL: ~100x100 tiles
Anything larger than that might just be too big for its own good.

I wish you could cull flagged meshes only

Cullable?

A new video showing some new things

I squashed a bug in the process of uploading this video, where the monsters were not correctly finding targets, mainly, they were not targeting the entity that hit them (which is what they’re supposed to do), in order to promote inter-monster battles.

@BPR: Cullable, or even Non-Cullable? That would be useful :slight_smile:

This looks very promising, keep going!
Are you thinking to add a random very simple “quest” generator, even if is just some doors and keys that you have to find to keep advancing in the dungeon…