Latest Entries »

In which I pass the torch.

I’ve been busy, but not on what you want.

Well, it’s Thursday again – my allotted slot for #iDevBlogADay – and I got nothin’. It was a tough week at the ol’ day job, and I haven’t had much time to think about game development at all, let alone come up with a poignant and thought provoking analysis of different death systems I’m thinking about for Dungeon Delver (coming soon) or an armchair treatise on the days when computer games were difficult enough to install and figure out, let alone beat (also coming soon).

So what does this mean? Well, I probably could have sat down and pounded out some half-assed post just to keep my position in the ranks of #iDevBlogADay bloggers, but I think you guys expect and deserve better. So I am going to relinquish my spot to the next developer yearning for the recognition, prestige, and heavy site traffic that comes along with a ride on #iDevBlogADay easy street.

Does this mean I’m going to stop posting regularly? Hell no. #iDevBlogADay was created to encourage us devs to share, and that spirit will live on here at Broken Platypus Games, even if my #iDevBlogADay hashtag belongs to someone else. I’ve got a head full of subjects I want to ramble on about, and I’m going to continue to shoot for at least once a week. Rules are rules, however, and while by virtue of posting this I have technically fulfilled my obligation to stay on the list, I think I will step aside and hand over the torch.

Changing the subject, or “Play some IF, dammit!”

Just so this post contains something iOS/game related, I am going to recommend, nay command, that everyone (yeah, even you) go and download the free Frotz for iPhone (and iPad) and play through Weapon. It’s a fairly quick single location interactive fiction.. took me about an hour to solve. If you haven’t played a text adventure in a long time, or ever for that matter, then you owe it to yourself to find a quiet spot, relax, clear your head and enjoy the simple beauty that is interactive fiction.

Alright, week three of #iDevBlogADay and I haven’t been kicked off yet!

This week I’m trying something different by putting up a screen cast of me drawing one of the creatures for Dungeon Delver and droning on about my creative process, or lack there of. It’s kind of long, and I think some people will dig it and others not so much. I probably could have found ways to cut it down but if someone is really interested in seeing the whole process, now they can.

So, without further adieu, here it is:
You should really go view it in HD at Vimeo. I don’t have a pro account so Vimeo won’t allow me to embed the HD version here.

Drawing a creature for Dungeon Delver from Broken Platypus Games on Vimeo.

Let me know what you think. I’d like to do more screen casts, so feel free to give suggestions on what would make the next one better for you, either in the comments or on twitter, or by shooting me an email at mattguest@gmail.com if you’re the type that prefers to be more discreet with your criticism.

Introducing Attack of the Nebuloids!

So, a little while ago, I was taking a break from Dungeon Delver work for a weekend and decided to throw together the beginnings of an action arcade style game for the iPad. After a day the game was feeling pretty solid, like it might just have a future, so I decided to go for it and keep on developing. Since then I’ve been alternating my free time between Dungeon Delver and the now officially announced “Attack of the Nebuloids!” (I know, I’ve talked about it a bit on Twitter, but this is the first mention on the site.)

Attack of the Nebuloids is an iPad-only arcade game that combines different modes mimicking classic arcade games like Space Invaders, Breakout and various SHMUPs. The different play styles are presented in waves, sort of like a rapid fire trip down arcade memory lane, but with many superfluous particle effects.

Here are some screenshots from the current build. Unfortunately the game, which runs smooth and beautiful on the device, runs very poorly in the simulator, so there’s no decent video of it yet. It’s kind of hard to capture the feel of the game in screen shots, but imagine everything on the screen moving really fast. It looks cool, trust me :)

So, I have this game in progress, and it’s moving along really nicely. I think that people will enjoy playing it, and I can’t wait to get it into their hands. So the next question is – am I going to make any money off of it? Truth be told, this game has been a blast to work on so far and don’t tell the fine app consumers out there, but I really just want as many people as possible to play and enjoy it. However, I also like money because I can trade it for other stuff I like.

Paid App

It seems fairly popular on the iPad app store these days for games to just straight up cost money. No demo or free version. I don’t think this is a viable option for Nebuloids because 1) I want as many people as possible to play it, and 2) I think most people pass right over paid apps unless they are featured or are of obviously superior quality. Not going to work for Nebuloids.

Free Demo / Pay For Full Game

The old standby since the dawn of computer games has been the shareware model. You get a good chunk of the game for free but to continue on you have to pay, usually after getting sucked into a story line or being teased with the exciting features and levels that await you in the full version. I suppose on the iPad it can’t really be considered ‘shareware’ since you can’t give your friend a copy of the app on a floppy disk, but the concept is the same.

I like this a lot better than the first option. Players get to taste your game without risk and if they like it, ideally, they buy it.

I think demo/paid app is definitely a good way to go, but I’m not feeling it for this game. The core experience of Nebuloids wants to be free, I can feel it.

Ad Supported

With the iAds platform out now we will probably be seeing even more people than we already are using this method of monetizing their apps and games. Ads are a good compromise between wanting to give something away for free and still making some cash.

I really don’t have any problem at all with ad supported apps and games, as long as the ads aren’t too intrusive, but no matter how out of the way their entire purpose for being is to draw the player’s attention away from the game. This might be fine for a game like Words With Friends, where there is no ‘world’ to disengage from, but for a fast paced arcade game, you don’t need any distractions beyond those planned by the designer. That said, I love to play ad supported games, because I don’t have to pay for them. Still, not for Nebuloids.

Upgrades via In-App Purchase

This is another popular one. I suppose it first started in MMOs, with character upgrades, items and weapons. In these games you’re paying to differentiate yourself from other players or to give yourself a competitive edge. From there the idea spread to games like We Rule and God Finger, where you can play for free, but it takes forever to do anything.. paying makes it go faster.

The first option that popped into my head for a game like Nebuloids was ship and weapon upgrades. Maybe you could purchase ships that differ both visually and in the way they play. Or perhaps players could buy weapons that aren’t otherwise available in the game, or to pass an area they’re having trouble with. I immediately shot down all of these ideas.

I don’t think an in-app purchase should alter the balance of gameplay, especially for a single player game. If a player can pay $.99 and get a weapon that destroys everything on the screen then it’s kind of like saying “This level is really hard, you’ll never get through it.. unless you purchase the BFG 10000 (way better than the BFG 9000, btw).” It just doesn’t sound right to me. I think with a little bit of brainstorming it might be possible to come up with good bonuses and extras that people would pay for in-game and not feel like they’re missing out if they don’t and cheated if they do, but it just doesn’t sit right with me for Nebuloids.

Additional Levels through In-App Purchases

Finally, the option that I’m pretty sure I’m going with – acquiring new levels through in-app purchases.

Attack of the Nebuloids! combines several classic arcade modes of play and presents them in rapid fire succession supported by a (fairly thin) storyline. The variety of play between different level types is what I think makes the game interesting and will carry the player through to completion and (spoiler alert) saving the world!

But what if someone really has a hankering for one of the level types in particular? Ordinarily they would have to play the game until they hit on one of the levels built in their desired mode. What I’m thinking is that in addition to the main story, players may be willing to purchase individual styles of play, either as level packs or continuous play modes.

Level packs would either provide a single level style, like “25 Alien Invasion Levels” or “25 Brick Breaker Levels”, or whole new story lines that combine different modes just like the main story does.. “The Andromeda Campaign – includes 50 unique levels.” This would certainly pave the road for more content (and purchases) down the road.

The other option I am considering would be to sell continuous play modes. As an example, players could purchase the “Alien Invasion Continuous Play” which would allow them to play an indefinite game of space invaders, with wave after wave either being randomly generated or perhaps several hand-made levels looped, faster and faster each time they come around.

So, what do you think, Internet people? Level unlocks are nothing new.. do you agree that they make the most sense for a game like this? Do you think people will want the ability to play a particular mode as much as they want, or do you think they’d be more interested in smaller but well thought out level packs? Or, perhaps you disagree with my strategy completely and think I should be headed in a different direction.

Please, provide any feedback you might have in the comments, or catch me on Twitter.

We all repeat ourselves.

Repetitive, menial, mind numbingly brainless repetitive coding tasks. You know what I’m talking about.. copying a list of variable declarations and pasting them right below just to turn them into a list of @property statements, then taking that same list and copying it into an implementation file to turn them into @synthesize statements. You turn the repetitiveness into a kind of mental macro, turn off your brain and let your fingers fly.. “Cmd-Left arrow, type ‘@synthesize’, select the type def, delete, down arrow, Cmd-Left arrow, type ‘@synthesize’, select the type def, delete, down arrow..”

Then, after you’re a few lines in you might think “Wait a minute.. I’m a programmer. I hold the power to bend this pile of silicon and plastic to my will. Shouldn’t my machine be doing this stuff for me? Oh well, only a few lines to go, then I can finally implement the bounce and splatter effects on the zombie brain explosions!”

Enough is enough.

The example of declaring properties and @synthesize statements has never really bothered be too much, mostly because this mental macro is so well rehearsed that by the time I start to feel like I might be wasting my time, I’m finished and can move on. Recently, however, I hit a repetitive coding task that I could not fathom doing by hand.

I was quite a ways into development on Dungeon Delver and came to a point where I realized that people may actually want to save their game. Dungeon Delver is very class heavy (sorry @SnappyTouch) and, since everything is randomly generated, there is a lot of hierarchical data that needs to be saved to cryogenically freeze and reconstitute a user’s unique game world. Luckily, Objective C has a handy way of doing this via NSCoder.

All I had to do was implement the encodeWithCoder and decodeWithCoder methods in the classes that need to be stored and it would take care of all the messy bits of writing and reading data, no muss, no fuss. This would make the whole process of saving and restoring a game session relatively simple, save for one facepalmingly obvious fact.. it was going to be a monumental task to add these functions to each of the relevant classes.

As an example, here is one of the smallest interfaces I needed to store:

@interface Dialog : NSObject {
   NSArray *textStrings;
   BOOL pausesGame;
   float timeToShow;
   
   float timer;
   int index;
   
   BOOL hasBeenRead;
   BOOL repeats;
}

And here are the ecode and decode methods that needed to be created for it:

////////////////////////////////////////////////
// DATA ENCODING / DECODING
////////////////////////////////////////////////

- (void)encodeWithCoder:(NSCoder *)coder
{
   [coder encodeObject:self.textStrings forKey:@"textStrings"];
   [coder encodeBool:self.pausesGame forKey:@"pausesGame"];
   [coder encodeFloat:self.timeToShow forKey:@"timeToShow"];
   [coder encodeFloat:self.timer forKey:@"timer"];
   [coder encodeInt:self.index forKey:@"index"];
   [coder encodeBool:self.hasBeenRead forKey:@"hasBeenRead"];
   [coder encodeBool:self.repeats forKey:@"repeats"];
}

- (id)initWithCoder:(NSCoder *)coder
{
   self = [super init];
   if (self)
   {
      self.textStrings = [coder decodeObjectForKey:@"textStrings"];
      self.pausesGame = [coder decodeBoolForKey:@"pausesGame"];
      self.timeToShow = [coder decodeFloatForKey:@"timeToShow"];
      self.timer = [coder decodeFloatForKey:@"timer"];
      self.index = [coder decodeIntForKey:@"index"];
      self.hasBeenRead = [coder decodeBoolForKey:@"hasBeenRead"];
      self.repeats = [coder decodeBoolForKey:@"repeats"];
   }
   return self;
}

As you can see, the functions themselves are fairly straight forward, but require just a little bit of logic when creating them. For each variable in the class that you want to store you have to determine the type and use the appropriate method of NSCoder to encode and decode it. Doing this by hand for as many classes and variables as I had would take forever.

Scripting to the rescue.

I’ve blabbered on long enough, so let’s cut to the chase.

Xcode’s scripting menu is accessed through the little scripting icon in the apple menu.. this little guy: script menu icon

In there you’ll find a bunch of handy scripts already waiting for you that conduct a variety of tasks, from commenting/uncommenting selected lines, sorting a block of selected lines alphabetically, and creating accessor definitions and declarations. It was this last one that caught my eye. In order to create accessor definitions, the script needs to be aware of the variable’s type, name, and whether it is an object or scalar type.. all of the information required to generate the encoding functions.

So, I cloned the Create Accessor Defs script and modified it to create the functions I required. The whole task took less than an hour and the end result was a script that gets me 95% of the way to having save and restore functionality in my game.

Here’s the completed script:

#! /usr/bin/python
# -*- coding: utf-8 -*-

# Known limitations:
#   - Multiword types (like "unsigned int") are not handled.
#   - The script will not recognise multiple variabes per line/type.
#      In order for the script to work you must change declarations like
#         int x, y;
#      to
#         int x;
#         int y;
#   - The script attempts to determine if the type is an object or not, but it is imperfect at detecting this

import sys
import string
import re

# ================== Script data ==================

# List of known scalar types (no ref-counting in accessors for these types)
knownScalarTypes = ("int", "unsigned", "char", "short", "long", "float", "double", "CGRect", "CGPoint", "CGSize", "NSRect", "NSPoint", "NSSize", "NSRange", "BOOL")


# ================== Templates ==================

preEncodeText = """\
////////////////////////////////////////////////
// DATA ENCODING / DECODING
////////////////////////////////////////////////

- (void)encodeWithCoder:(NSCoder *)coder
{
"""


postEncodeText = """\
}

// init this instances data from the NSCoder
- (id)initWithCoder:(NSCoder *)coder
{
   self = [super init];
   if (self)
   {
"""


postDecodeText = """\
   }
   return self;
}
"""


objectEncodeDecls = """\
   [coder encodeObject:<ivar> forKey:@"<ivar>"];
"""


objectDecodeDecls = """\
   <ivar> = [coder decodeObjectForKey:@"<ivar>"];
"""


scalarEncodeDecls = """\
   [coder encode<type>:<ivar> forKey:@"<ivar>"];
"""


scalarDecodeDecls = """\
   <ivar> = [coder decode<type>ForKey:@"<ivar>"];
"""



# ================== Script ==================

# Get input lines
inputLines = sys.stdin.readlines()

# Strip comments and extra whitespace
commentRE1 = re.compile(r"[   ]*\/\/.*$")
commentRE2 = re.compile(r"[   ]*\/\*.*\*\/[  ]*")

newInputLines = []
for curLine in inputLines:
    curLine = re.sub(commentRE1, "", curLine)
    curLine = re.sub(commentRE2, "", curLine)
    curLine = curLine.strip()
    if curLine != "":
        newInputLines.append(curLine)

inputLines = newInputLines

# Process each line

# Subexpressions:
#     1 - IBOutlet decl
#     2 - First letter of Type name (without pointer *'s)
#     3 - Type name (without pointer *'s)
#     4 - Pointer *'s from type
#     5 - Leading underbar(s) of variable name
#     6 - First letter of variable name
#     7 - Rest of variable name
declRE = re.compile(r"^(IBOutlet)?[    ]*([a-zA-Z])([_a-zA-Z][_a-zA-Z0-9]*)[  ]*(\**)[    ]*([_]*)([a-zA-Z])([_a-zA-Z0-9]*)[  ]*;")

typeRE = re.compile(r"<type>", re.MULTILINE)
keyRE = re.compile(r"<key>", re.MULTILINE)
capKeyRE = re.compile(r"<capKey>", re.MULTILINE)
ivarRE = re.compile(r"<ivar>", re.MULTILINE)

encodeText = ""
decodeText = ""

for curLine in inputLines:
    # Match the line and extract the subexpressions
    matchObj = re.match(declRE, curLine)
    if matchObj != None:
        # Note indices are 1 less than subexpression numbers in the comment above
        subexps = matchObj.groups()
       
        isObject = True
        isArray = False
     
        t = subexps[1] + subexps[2]
     
        if t in knownScalarTypes:
            isObject = False
     
        # Figure out the substitution strings for the accessor templates
        if subexps[3] != "":
            curType = string.upper(subexps[1]) + subexps[2] + " " + subexps[3]
        else:
            curType = string.upper(subexps[1]) + subexps[2]
         
      # Fix BOOL type for use in the coder function name
        if curType == "BOOL":
            curType = "Bool";

        curKey = subexps[5] + subexps[6]
        curCapKey = string.upper(subexps[5]) + subexps[6]
        curIvar = subexps[4] + subexps[5] + subexps[6]
       
        # Build the result
        if isObject:
            curEncodeText = objectEncodeDecls
            curDecodeText = objectDecodeDecls
        else:
            curEncodeText = scalarEncodeDecls
            curDecodeText = scalarDecodeDecls
       
        curEncodeText = re.sub(typeRE, curType, curEncodeText)
        curEncodeText = re.sub(keyRE, curKey, curEncodeText)
        curEncodeText = re.sub(capKeyRE, curCapKey, curEncodeText)
        curEncodeText = re.sub(ivarRE, curIvar, curEncodeText)
       
        curDecodeText = re.sub(typeRE, curType, curDecodeText)
        curDecodeText = re.sub(keyRE, curKey, curDecodeText)
        curDecodeText = re.sub(capKeyRE, curCapKey, curDecodeText)
        curDecodeText = re.sub(ivarRE, curIvar, curDecodeText)
       
        encodeText += curEncodeText
        decodeText += curDecodeText
     
code = preEncodeText + encodeText + postEncodeText + decodeText + postDecodeText
print code,

So there you have it. All I had to do is copy the variable declarations for an interface to my clipboard and hit the shortcut key I assigned to the script in the scripts window to put the functions on the clipboard. A huge step towards saving my game and my sanity.

Unlimited possibilities.

Scripting is one of those things that is either ingrained into your psyche as a developer or not. I know plenty of programmers that would be perfectly happy copying and pasting and modifying code over and over and never give it a second thought. I also know a much smaller group of guys that won’t even move a file without considering writing a Bash script to do it for them.

As you can see, the potential for what you can do with scripting in Xcode is pretty incredible, and if you can get yourself comfortable with one of the common scripting languages (the sample scripts in Xcode are a mix of Bash scripts, Python and Perl) and force yourself to look at the act of coding as something that can be improved by more coding then you’ll be well on your way to a higher plane of development.

So, the next time you find yourself executing one of those ‘mental macros’ over 50 lines of code, and the realization strikes you that your fingers are getting sore and you’re not getting paid by the hour, hopefully you’ll realize that a better way is waiting for you up there in that mysterious little squiggly scroll icon.

IDevBlogADay

Broken Platypus Games is proud to be participating in the IDevBlogADay initiative being moderated by @mysterycoconut on twitter. The idea is to get developers to sign up for a particular day of the week and  commit to publish a blog post every week on that day, guaranteeing that fresh content is always flowing from the iOS game development community.

Here’s the list of participating blogs:

You can follow the entire list of blogs by subscribing to this rss feed, or search for the #idevblogaday hashtag on twitter to follow the fun in real-time!

New Gameplay Video

First off, if you are at all interested in Dungeon Delver’s progress then you should really be following me on twitter (@brokenpgames) because I post little updates there a heck of a lot more than I update this website.

However, since my traffic logs show that someone out there is still waiting for an update, here is a video I took of the gameplay a few days ago showing off the latest addition to the engine – ranged combat. So far I’ve added bows, but the tile highlighting and picking will be used for other actions as well, such as spells. I’ll be adding a few other ranged weapons as well.. probably slings and throwing daggers.

Dungeon Delver Ranged Combat from Broken Platypus Games on Vimeo.

The engine is just about complete at this point. The few things left to do are state save and load, which should be fairly straightforward using NSCoder, tightening down the skill and leveling system, and adding a screen for starting a new game or continuing. After that the engine will be feature complete (for this game anyway, lots of new features planned if I make a DD2) and I’ll get to concentrate on what I really want to do – make tons of monsters, items, and story.

It’s been a long road, but I think I can see a light peeking out from around the next bend in the tunnel.

Still around, still working

I haven’t updated the site in a while, but wanted to stop in to assure my hundreds, nay – thousands, of loyal fans refreshing the brokenplatypus.com website 30 times a minute that I am in fact still working on Dungeon Delver! Things are coming along nicely, in fact. I have randomly generated dungeons linked together in a currently endless procession, populated at this time exclusively by little purple blobs and giant rats.

I have been updating my Twitter account (@brokenPGames) quite often with updates and screenshots as I’m working, so if there is actually anyone out there interested in Dungeon Delver’s progress then that is where you’ll see the freshest, most succulent morsels of information.

I’ll be working on the character stats and combat system in the next week or two, at which time I’m sure I’ll the waxing philosophic about mechanics and various methods of simulating combat.

rat

Look out, it’s a giant rat!

In all RPGs – computer, console, and pen and paper – one of my all-time favorite classes to play is the rogue. I love sneaking around, stabbing things in the back, and pulling off stealthy head shots from afar. The only complaint I’ve had is that it’s difficult to play a true stealth character in a lot of games because they don’t provide experience for avoiding conflict.

In many pen-and-paper games, the game master can provide experience for resolving a situation, whether it was through combat, negotiation, or completely circumventing it somehow. This is difficult to pull off in a computer game. It’s really easy to give out experience for killing an enemy, but what if you used stealth to avoid combat, or froze the enemy with a spell and then high tailed it out of there? Should you get experience from that?

This is a question I’m putting a lot of thought into for my game. I would like there to be real differences in how a player plays depending on their character. If you work up your stealth attributes, I don’t think you should be punished for avoiding combat. The question is when is it appropriate to award experience for this, and how do you guarantee that players can’t double dip, avoiding the enemy and gaining experience and then killing it for more.

One idea I had was to give each enemy a max experience value that gets transferred to the player bit-by-bit for different actions. Here’s a scenario:

Goblin: 100 max XP
Player turns on a stealth skill and manages to sneak past the goblin, who is within 5 squares of the player. Player gets 20xp for this, goblin now has 80 left in its pool.
Player comes back that way again and sneaks past – another 20 point transfer, goblin has 60 xp left.
Player tries to sneak past again and is noticed, combat ensues, player kills the goblin and gains the remaining 60xp.

If the player hadn’t killed the goblin, then they would have earned 40xp from it. They’re still not rewarded fully for avoiding it, but I think by tweaking the numbers it would be enough that playing a non-combative stealth character would be a viable option.

I’m still not sure how to reliably detect a non-kill defeat though. I could see a rogue character scoring a hit on a creature to stun it and then running out of the room, locking the door behind him to trap the creature. It seems like that should deserve some XP, because it’s a more true to character action than standing there pounding on the enemy like a warrior, but how best to detect those scenarios and award them? The answer is that I’m not sure yet.

Another idea would be to implement offensive skills that would be more appropriate to a rogue character. If a rogue builds a trap on a square and then lures a creature into it then they get experience for the kill. Running away or avoiding a creature wouldn’t gain xp, but passively defeating it still counts. And then there’s always the old ranged attacks standby.

Getting off of the rogue class specifically, I’m also undecided on the type of skill system I want to put into the game. I’d like to keep it casual and avoid having the player distributing skill points or picking powers, but feel that the ability to mold different types of characters through play should be integral to the game.

One idea I have is to split skills into several categories, like “Rogue” “Warrior” and “Mage”. The player starts with an equal skill in all three categories and as they do things in the game experience points accumulate in the different pools accordingly. Attacking something with a sword puts the XP into warrior, using stealth or picking locks gives you rogue points, and casting spells or using scrolls increases mage. When the total XP from all groups combined hits a threshold then you gain a level and your general stats go up, but modified by the distribution of points. So, a player that has done a lot of head on combat will gain more hit points per level than a stealth character, and a magic user will gain more mana than a warrior. When the points in a particular category reaches a threshold then new skills may become available. So, a character with a lot of warrior points might be able to conduct a spin attack that hits all squares around him at once, while a stealth character might get a tumble action that allows them to slide several squares in one round. These skills could be a bit randomized to add to the Roguelike feel of the game. Each time you play a new game different sets of skills could be given to your character in each category to keep it interesting.

As you can see I’ve got a lot to ponder here. If you have any comments or ideas, please step forth and speak your piece.

Interface begining to take shape

I’ve had the control scheme for Dungeon Delver set up like several other roguelikes in the app store, using the top of the screen to move up, bottom to move down, left – left, right – right. I found after a lot of playing that this really becomes unfomfortable after a while. I think it’s important that the game can be played with one hand, and this control scheme starts to wear on your hand pretty quickly. So I’ve decided to go with a d-pad. It will be trivial to keep both schemes, so I may end up making it an option.

Another thing I keep repeating to myself is that this is going to be a fairly casual Roguelike. I don’t want anyone to have to pour over a manual to figure it out, or memorize obscure commands. I understand that this is half the fun in a real Roguelike, but that’s not what I’m aiming for with this game. With that in mind, I am also adding interface buttons for all of the major actions a player can take. I’ve added a button to open and close doors already, and there will be others to use your queued attacks, rest, etc. Actions like drinking or eating something will be in the inventory screen, like any modern rpg.

Here’s another video showing my first go at the d-pad. I’ve added the door button already, so you can see that in action as well. It may be hard to tell from this video, but in your hand this is extremely natural and easy to use.

Dungeon Delver – New Control Schme from Broken Platypus Games on Vimeo.

I also added a smooth transition for the player when he moves from tile to tile.

I wonder what’s around that corner?

I have added a line of sight algorithm to Dungeon Delver. It’s pretty simple, and there are a few places where it can get a little wonky, but I after playing with it for a while, I think it definitely falls into the “good enough” category.

The algorithm is very simple:

  • For each tile being drawn on the screen attempt to draw a line using Bresenham’s line algorithm from the tile to the tile occupied by the player. If you hit any blocking tile, like a wall or closed door, then the tile can’t be seen.

This algorithm is pretty brute force and could be made more elegant and optimized quite a bit, but since we have a fixed (and rather small) screen to work with on the iPhone, I’m not too concerned. It runs extremely fast in practice.

I had already built in for each tile to support a lighting value that can set the shade of a tile using cocos2d’s setColor function. This value is used to set tiles that have never been seen to black, and tiles that have been seen but are not currently visible to 50% lightness, making them darker than visible tiles. Once I get objects and creatures into the maps, they will only be drawn if they are on currently visible tiles.

I also added tile groups, which link tiles to a single entity, like a hallway or a room. When the player steps into a room, all of the tiles associated with that room automatically become visible. In practice I liked this better than just letting the algorithm do its thing as it cut down on some of the artifact problems of using Bresenham’s algorithm, which is really fast but can be a little flaky and imprecise at times. I’m not necessarily going for precision here, just what fells right and revealing an entire room when you enter it feels right to me at the moment.

Anyway, enough blabbering. Here’s a video of it in action.. also note the smooth map scrolling, which I think adds some polish while maintaining a traditional tile-by-tile movement feel:

Dungeon Delver LOS test from Broken Platypus Games on Vimeo.

And here’s the source to the main function that makes it happen for anyone who’s interested:

/////////////////////////////////////////////////////////
// LINE OF SIGHT
/////////////////////////////////////////////////////////

-(BOOL) playerCanSeeTile:(CGPoint)pos {
  Tile *t = [map getTileAtX:pos.x y:pos.y];
  if(t.type == EMPTY_TILE) return FALSE;

  Tile *playerTile = [map getTileAtX:player.tilePos.x y:player.tilePos.y];
  if(playerTile.type == FLOOR_TILE)
  {
    if(t.type != HALL_TILE &amp;&amp; playerTile.blockId == t.blockId) return TRUE;
  }

  float x1 = pos.x;
  float y1 = pos.y;
  float x0 = player.tilePos.x;
  float y0 = player.tilePos.y;

  BOOL steep = abs(y1 - y0) &gt; abs(x1 - x0);
  if(steep) {
    int t = x0;
    x0 = y0; y0 = t;
    t = y1;
    y1 = x1; x1 = t;
  }

  if(x0 &gt; x1) {
    int t = x0;
    x0 = x1; x1 = t;
    t = y1;
    y1 = y0; y0 = t;
  }

  int deltax = x1 - x0;
  int deltay = abs(y1 - y0);
  int error = deltax / 2;
  int ystep;
  int y = y0;
  if(y0 &lt; y1) ystep = 1; else ystep = -1;

  // Top Tiles contain doors and other obstacles that sit above the floor.
  Tile *topT;

  // check the tiles using bresenham's algorithm
  for (int x=x0; x
  {
    if(steep) {
      if(!(y==pos.x &amp;&amp; x==pos.y) &amp;&amp; !(y==player.tilePos.x &amp;&amp; x==player.tilePos.y))
      {
        t = [map getTileAtX:y y:x];
        if(t.type != FLOOR_TILE &amp;&amp; t.type != HALL_TILE) return FALSE;
        topT = [map getTopTileAtX:y y:x];
        if(topT.type == DOOR_TILE &amp;&amp; !topT.door_open) return FALSE;
      }
    } else {
      if(!(x==pos.x &amp;&amp; y==pos.y) &amp;&amp; !(x==player.tilePos.x &amp;&amp; y==player.tilePos.y))
      {
        t = [map getTileAtX:x y:y];
        if(t.type != FLOOR_TILE &amp;&amp; t.type != HALL_TILE) return FALSE;
        topT = [map getTopTileAtX:x y:y];
        if(topT.type == DOOR_TILE &amp;&amp; !topT.door_open) return FALSE;
      }
    }

    error = error - deltay;
    if(error &lt; 0) {
      y = y + ystep;
      error = error + deltax;
    }
  }

  return TRUE;
}
Powered by WordPress | Theme: Motion by 85ideas.