Rogues' Redemption - roguelike with pixel graphics

This game started out as an experiment to see if I can successfully generate dungeons and other types of level in Defold - the code can be fairly complex depending on how far you want to take it.

Right now, I’m just using a test level to get the basic game-play working. The game will be turn-based and function as one would expect from such a game. Pixel Dungeon and Cardinal Quest II are my main sources of inspiration.

It’s very early days and as you can see I have a very basic level with the player moving about in revealing more scenery as it comes into his line-of-sight.

early demo of “fog of war” functionality

Well over 95% of the game still to do!

  • enemies to encounter
  • various items to collect and use
  • items to use in crafting
  • secrets to discover
  • side quests to take on
  • NPCs to interact with

Depending on how well things go, this list will likely change quite a bit.

Thanks for reading!

9 Likes

Sweet! Roguelikes (in the traditional hard core sense, not the watered down stuff being labeled as roguelikes nowadays) is one of my favourite genres! I’m really looking forward to follow this project. Good luck!

Oh, whoa. This is just what I’m looking for. I’m getting started in game dev, and I’m thinking starting with Unity is a bit overkill for the scope of the roguelike I’m wanting to make. Would you be willing to share where you’re at with this project? I’d love the opportunity to poke around in something like this as a springboard for my project.

1 Like

Haven’t got much further with this yet. I’m in the middle of changing jobs and moving house so haven’t had the time. In the new year though, I’ll be able to continue development.

4 Likes

Development on Rogues’ Redemption has restarted! :grin:

It’s still at an early stage but some functionality is starting to come together. After some experimentation with different approaches, the field of view/fog of war is now working reliably. Previously it was displaying various artifacts, projecting through walls and such. I’m happy with it as it is but may add feathering to the edges to make it more visually appealing.

The turn system is now working. That is, the player takes a turn, then any monsters in range take their turn. This was actually not as tricky as expected and runs glitch-free (for now!).

Monsters have their own field of view and will give chase if they see you. This will be expanded to make them harder to escape from. Right now, if you duck behind a wall, the monster will revert to hanging around waiting for something to happen.

Basic melee attacks are also working but will need a good deal of expansion to deal with attack, defence, chance etc. values. There will also be some ranged weapons in the game such as the bow and arrow combo.

The inventory system is partly working - the player is able to pick up objects found in the dungeon and see them displayed in the inventory box. There are 5 special locations in the inventory - left hand, right hand, armour, ring and necklace slots. This may change in the future depending on how well the game works with it like this.

Overall, I’m aiming to satisfy most of the points outlined in the Berlin Interpretation of a Roguelike. Procedural level generation is proving quite a challenge so far so I’m currently working with a handmade test level.

Next on my todo list:

  • Handle doors correctly - currently the player is invisible in a doorway
  • Chest handling code
  • Finish inventory handling code
  • Expand combat system

Plus a ton of other things, I’m sure.

Thanks for reading - I’ll have another update in about a week.

6 Likes

Very nice! Let me know if you need help with playtesting. Roguelikes (the traditional ones that actually resemble Rogue, Moria, Angband etc) have a special place in my heart!

3 Likes

There are various ways to implement field of view functionality in a roguelike. Initially I attempted to project from each map tile back to the player unhiding the tile if the ray makes it back to the player without colliding with a solid tile. Although this kind of worked, it was problematic both technically and visually. There were a lot of artefacts and the code to sort this out was complicated and not eligant.

So I re-wrote the code to mimic a radar of sorts. Rays are projected out from the player and each tile that is reached is then unhidden. Once the ray hits a solid tile it stops.

Technically, this is a simple approach to the problem but provides good and consistent results. Initially, the radar did a full 360 degree sweep in one frame but this was very slow on Android so it’s now chopped into 16 slices; this still achieves nearly 4 full sweeps per second. I quite like the way this suggests the hero is quickly looking around the room rather than the whole room suddenly popping into view when the door is opened.

The gif is slower than the actual radar in the game.

3 Likes

I’m surprised that it was slow. When you say that you did a 360 sweep, in what increments did you trace lines out from the player’s position? Do you have a limited field of view or can the player see an infinite distance?

It scans in increments of 0.025 radians, which is about 1.5 degrees at a time and scans out to the edge of the screen at most. It does this in 16 slices. Here’s the code if anyone is interested - this is by no means the best solution to the problem but it does work reliably:

local data = require ("main.data")

function init(self)
	self.scan = 0
	self.levelurl = string.format("level%d:/level#tilemap", data.level)
end

function update(self, dt)
	local p2 = vmath.vector3(0,0,0)

	for a = self.scan, self.scan + (math.pi/8), 0.025  do
		
		p2.x = math.sin(a) + data.playerpos.x
		p2.y = math.cos(a) + data.playerpos.y
		
		lineofsite(self, data.playerpos, p2)
	end
	
	self.scan = self.scan + (math.pi/8)
end

function lineofsite(self, p1, p2)
	local v = p2 - p1
	local len = math.sqrt((v.x * v.x) + (v.y * v.y))
	
	v.x = (v.x / len) * 4
	v.y = (v.y / len) * 4
		
	local p = p1 + v
	local c = false
	local s = 0
	
	while c == false and s < 22 do
		p.x = p.x + v.x
		p.y = p.y + v.y

		local t = data.gettile(self, p.x, p.y, "world")
		if t >= 280 then
			c = true
		end

		data.settile(self, p.x, p.y, "fog", 0)

		s = s + 1
	end
	
	--msg.post("@render:", "draw_line", { start_point = p1, end_point = p, color = vmath.vector4(1, 1, 1, 1) } )
end

Some things that come to mind:

  1. Nitpicking but what the hell: lineofsight, not lineofsite
  2. When iterating along a line I’d look into using Breshenhams line drawing algorithm. There’s no math.sqrt() involved and it’s generally considered fast.
  3. If you do a lot of calls to functions that are set on tables (such as math.sin) it’s a good idea to cache those functions in local variables. This way there’s no table lookup every time you need to call the function. Check page #3 of this Lua Performance Gems: https://www.lua.org/gems/sample.pdf. You need to be calling the function a lot for it to really be measurable, but in games performance is important, and who knows, maybe you need to start calculating field of view for many agents every frame and then it really matters.
  4. You can probably skip many rays if you hit something that blocks line of sight near to the player. In that case it’s very likely that many of the subsequent rays being cast will pass through the same blocking ray and in that case it’s pointless to even cast those rays in the first place.
3 Likes

As @britzl mentions, a Bresenham algorithm would probably be suitable for this. (link found here)

Also, I came to think of maybe adapting a floodfill of sorts, and again, googled it, and found that someone (ofc) already had had the same idea: Dijkstra + line of sight. Ofc, as is, the result is a bit “blocky”, but I kind of like that in a rogue like.

Now, I think I found my programming exercise for the day :slight_smile:

4 Likes

Lots of new stuff in this update! I’ve been busy on many aspects of Rogue’s Redemption.

First of all, I’ve decide to target Android for this particular game. I’m writing it really as a game I’d like to play myself on the go. Somehow I find most mobile games disappointing in one way or another so would like to make something that’s actually good fun to play on a mobile device.

The interface has been developed a bit more with the addition of health and xp bars. Also a profile icon has been added in the top right of the screen. This will be used for various things, the specifics of which have yet to be decided.

The player can actually die now! The game feels more like a real game now that’s possible. Combat is still arbitrary with fixed amounts of damage being done on each attack. I’m not familiar with D&D and don’t particularly want to be so all the ‘chance’ combat events will be kept minimal and will behave more as you’d expect. One thing I don’t like about some roguelikes is when the random and luck elements seem to often dictate the outcome of a game.

30+ of the planned 60+ usable items in the game now spawn from chests, boxes are as drops from dead monsters. All the code to actually use the various items has yet to be written.

There are a few sound effects now for various events and actions. This really helps build the atmosphere of the game. These will obviously be added to and some suitable music added too.

The line of sight code has been re-written twice now! The latest incarnation uses Bresenham’s line-drawing algorithm as suggested by some of the guys here. It’s currently much slower than my previous vector based code but it can be optimised greatly. Right now it checks every pixel of the line and really only needs to check about 1 in 4 or even 1 in 8.

There is now a ‘ticker’ which saves 4 lines of text displaying the last 4 notable events to happen. Most roguelikes seem to have this and I like it so there we go.

The greatest challenge at the moment is collision detection. Defold’s collision shape implementation isn’t well suited to a grid-based game like a roguelike. I really need a way of just checking a tile for an enemy and act accordingly. With the loosely-coupled nature of Defold, I’m honestly not sure how to do this. I’m sure a solution will present itself soon enough - it always has done thus far!

Thanks for reading. Here’s a screenshot from the latest build:

7 Likes

Looks really nice! Can’t wait to play it! :slight_smile:

1 Like

I agree, it looks great!

Do you really have to use Defold’s collision detection for a grid and turn based game such as a roguelike? I would create a full representation of the level in a Lua table structure and do FOV, pathfinding and all of that stuff on that structure and only use the game objects as a visual representation of that main data structure.

1 Like

Lots of “under the hood” development has been happening this week as well as some more visible additions.

Part of the roguelike mix is inventory management - I’ve further developed the inventory code which now allows the player to pick up/drop and use or equip various items. There are a few more bits to finish off this part of the game and that should be done in the next few days.

I’ve re-used some code from Psychon 2 - that is, the mini map code. Some re-arranging was needed as now the map is slowly unfolding before you and the minimap reflects this - in Psychon 2 the map was generated at the beginning of the level but now it needs to continually be generated because it keeps changing.

The interface and osd has also had some further tweaks and is (I hope) near to being finalised. I’ve been spending more time testing the game on an actual phone to make sure it works nice and smoothly - so far so good :slight_smile:

Monsters now have little health bars over there heads.

Functionality for the first trap to go in the game is in and working - a very simple trap that looks like a mushroom and explodes poisonous spores everywhere when you go near it. Monsters can also trigger traps so it can be quite fun tricking them into blundering into one :grin:

Still lots to do - more items to add, quests to take on and all the balancing / progression through the levels to sort out.

As always, thanks for reading and here are a few screen-shots.

8 Likes

Cool, it looks great! How many equipment slots will you have? Main hand+off hand, chest, helmet, boots, ring, amulet?

1 Like

Thanks! And yes, there are 6 equip-able slots - main hand, secondary hand, armour, helmet, amulet and ring. There’s some stuff in the wrong slots in the screenshot above but it’s been fixed now!

Should look something more like this:

6 Likes

They say rewrites are the bane of all roguelikes - thus far, I’ve known this to be 100% true. This week I’ve rewritten most of the collision system, parts of the spawning systems and various routines that deal with the various coordinate systems used in the game (screen, map and world). The code is ‘feeling’ more cohesive and stable now and I’m confident the game can now be more easily expanded.

Ranged Attacks

Having completed work on melee attacks near the beginning of development, it was time to get the ranged attacks working. So far, the fireball attack is the only available ranged attack but the code can easily be reused for any number of other ranged attacked. Having these available to the player increases the strategy element of the game significantly.

Mana

The player now has mana points (MP) to use with various spells. The aforementioned fireball is currently the only functioning spell but the mana system is ready to be used for any number of other spells in the future. Some of the supporting stuff such as the ability to drink mana potions is also done.

Balance

I’ve started to think more about balancing the game and tidied up a few things. I’ve implemented a system to prevent stuff spawning in the wrong places or on top of other stuff. The types of monster now get steadily harder as you progress through the levels e.g. you’ve only vampire bats and goblins to deal with on level 1 but around level 15 you’ll be tackling trolls and dragons.

Progression

There is now a complete game cycle - a basic front end leads you into the game and you can progress through levels building up your character before eventually dying and returning the the front end to start again. Dying happens a lot in roguelikes!

Various other areas of the game continue to be gradually added to and improved. This following week will mostly be taken up with adding functionality for weapons, spells and other items. I may even start thinking about quests.

6 Likes

Just one month ago, I began developing Rogue’s Redemption. Although it’s been hard work, I’m amazed at how much has been achieved in such a short space of time. I continue to find Defold very rewarding and quick to use.

This week, I’ve spent most of my time balancing various elements of the game and adding items and effects. The various collectable items now show up in a more orderly fashion as the player progresses through the game - so you wont be seeing the best weapon in the game popping up on level 2 any more. This will need more tweaking and testing at a later date once some other stuff has been finalised.

I’ve also added various scrolls, potions and spells. The particlefx feature of Defold has been great fun (and quick) to use and try out various ideas for special effects. The game continues to run fast on Windows and both my Android devices.

Also the usual fixes, tweaks and minor changes you’d expect during development of any game.

The first NPC is also present in the game though he has no real functionality at this point. He’ll be a mobile shop of sorts and the player will be able to buy and sell items with him when he pops up every few levels.

There are a couple of traps working now - the poison trap and the sticky trap. I’ll be adding more as the ideas present themselves.

For the following week I’ll be working more on NPCs, quest givers etc.

Some screens of various spells and scroll effects:-

8 Likes

Looks great!

2 Likes