Thursday, February 28, 2008

Games Should be Fun - All the Time

I was playing Resident Evil 4 on the PS2 last night. It's a very graphically impressive game. However, it does have a major flaw (which it shares with most other games) - it's not always fun to play.

[Spoiler warning] If anyone out there has RE4, it's the bit where you have to fight the first giant/ogre thing (see right). It's one of those boss battles where you have to guess where the weak spot is, and also what else you have to do. If you don't work it out, you'll be stuck on the level forever, and the only way I can see of working it out is to spend a whole day on it, or look on the internet. In this case, you have to shoot it in the head until something bursts out of it's neck, and then run up to it and jump onto its back and stab this thing. You have to do this 3 times as well, so hopefully you won't run out of ammo.

The problem with the bit in question, as well as getting a bit tedious, was that it is preceeded by a 30-second movie clip that you can't skip through. Every time you die, you have to run back to the same point in the game, and then sit through the same clip again. Why do companies think that we want to watch the same clip over and over again? To massage their ego?

The various GTA (and a lot of other) games suffer from this problem as well. If you fail at a mission for example, you then have to go through the build-up to the mission all over again (reloading the game, running to that area of the map to get the mission, run to the area of the map where the mission takes place etc..). This wouldn't be a problem if these bits of the game were fun, but running across a map is rarely fun, especially the second (or third...) time round.

The bottom line is games should be fun. All the time.

Monday, February 25, 2008

Laser Tactics - CPU v CPU

One of the best ways of testing your AI is to get it to play against itself. Often this isn't possible as most computer AI is very simplistic, involving standing still and shooting at the player, or following a set route and waiting for the player to trigger some change.

However, the AI in Laser Tactics is quite advanced (IMHO), and there is AI available for both sides in nearly all the various missions and objectives. So I quickly added the code so it's possible to select AI for both sides (previously you could only choose it for one side). The game also has a "Ghost" mode, which allows a player to view the game through the eyes of a unit that is CPU-controlled.

Once I'd set all this up, it's actually great fun watching the computer play against itself, especially when the missions actually have objectives (meaning it's not just a case of watching the units wander around shooting on-sight). And of course, it's ideal for checking that the AI works well and doesn't have any of the usual problems that AI suffers from (like get stuck in a loop or end up wandering in the wrong direction). Add to this the "randomly-generated map" option and it almost feels like I'm watching two humans battle each other. Place your bets now!

Monday, February 18, 2008

Blindingly Obvious Java Tips #2

Todays tip is all about getting your game to run at a consistent speed. You may not think it a problem on your new game, since you probably crammed in enough features to keep the CPU busy for just the right amount of time, but once you try and run it on a Cray (since surely that must have a JVM??) you may find it slightly unplayable.

So, to stop it running too fast: First, define a variable of type "long" at the start of your program for how long you would like the program to take over each game loop. In the example below, I've chosen the name "LOOP_DELAY" for this var, and I usually give it a value of around 25. You'll probably want to tweak this amount. Also, declare another long called "start_time".

Anyway, at the start of your "game loop", write something like:-

start_time = System.getCurrentTimeMillis();

This will store the current time when the computer started the game loop. Finally, at the end of your game loop, write something like:-

long wait = LOOP_DELAY - System.currentTimeMillis() + start_time;
Thread.sleep(wait);

(You'll need to wrap this in a try/catch BTW). This bit of code will make the program pause for a certain amount of time at the end of each game loop, that time being the number of milliseconds you wanted it to take over each game loop, minus the amount of time it took to actually process the code in your game loop. This will cause each game loop to take a consistent amount of time, assuming that the time it takes to process the code in the game loop isn't longer than the time you want it to wait for!

Friday, February 15, 2008

Announcing Laser Tactics!

If you've read one of my earlier article, you'll know that I've decided to "re-released" Nuclear Graveyard under a new name - "Laser Tactics" (kindly suggested by Charlie). And now I've finally got round to it. I've given it a few more tweaks, and I'm pretty pleased with it all. I've taken a few more screenshots to celebrate, which I'll be sticking on the website as soon as I can.

The only problem with it is that it's not an FPS, and it's not turn-based, and most people expect a game like this to be either one or the other. If anybody reading this decides to give it a go, please bear this in mind: Your unit's APs are replenished in realtime!


Thursday, February 14, 2008

Blindingly Obvious Java Programming Tips #1


(This is number #1 in my intended series of Programming tips for Java. They are probably blindingly obvious to most people, but they have passed me by until recently, and it doesn't do any harm to mention them in case anyone else has missed them to).


Daemons

Todays tip is all about setting threads as "Daemons".

I used to have a problem in my games that used multiple threads, in that it was very hard to get them to actually end. Even when all the windows were closed, there was still a process running in the background. I usually fixed this by adding a "System.exit(0);" to the code when I wanted it all to end, but this is certainly not the best way to go about it.

A Java program ends when there are only "daemon" threads running. This means, in short, that any thread which isn't what you would call the "main program thread" should be marked as a daemon so that it ends when the main program thread ends. This is simply a case of writing "mythread.setDaemon(true);". Incidentally, threads are not daemons by default.

Wednesday, February 13, 2008

Programming Affects the Mind

I've long suspected that spending too long programming affects the way the mind works, and I've finally come across a quite-good example:-

My wife innocently asked me if our car boot was locked. Being a programmer, where accuracy and logic is paramount, my mind was instantly plunged into a spagetti of possible answers and their respective problems.

Our car's boot (trunk for Americans) can only be opened with a key or by using the lever by the side of the drivers seat. There is no button on the boot to open it if the car is unlocked, which it was. So was the boot actually unlocked? One possible answer is "no", since it couldn't be any more unlocked than it was. However, giving this answer implies that it was possible for her to go out and open the boot, but I'm not sure she knows about the lever (since she's not a driver) and she doesn't have a key, this wouldn't work. So is the answer "yes it is locked", since the boot cannot be opened directly? But this can't be correct, since it is openable without a key, which is presumably the definition of "locked". Is the correct answer "sort of"? No, not if you want to be helpful. Is the correct response to explain how the various boot locking mechanisms work or describe where the lever is? Probably not, since it would take too long.

In the end I just ummed and ahh'd and said I'd open it for her.

Monday, February 11, 2008

The Problem with RTSs

One problem is knowing whether to put an apostophe in the word "RTS's". However, the other problem I have with them is always feeling that it's pointless trying different actions; either they won't make any difference, or it's all down to chance anyway.

I really want to enjoy RTS's, ever since I played what I think is the very first one: Stonkers (not Dune II!). I've not played many of the later ones, but I've played C&C, StarCraft, Age of Mythology, and quite a few free ones, and even written my own.

The typical scenario goes like this: I select a group of units, move them towards the enemy, and err, repeat. All I can do now is watch them do battle. Maybe my units will win, maybe they won't. Should I try some newfangle tactics? Does it make any difference if I have some units on the left side of the enemy and some on the right side? Or maybe I should build a tank instead of two foot-soldiers? Is it better to have a tank than two footsoldiers? I don't know. All I know is the units keep shooting at the enemy and eventually some of them die. The tank is more powerful but has a slower shot rate, but I can't be bothered to check the "stats" to see if the more powerful gun with a slower shot rate is better than two weak guns with a faster shot rate.

I might be fighting another small skirmish in another part of the map while this is going on. When I go back to the original skirmish, some of my units have survived and the enemy seems to be dead. Or did they retreat? And if they did, how much damage was inflicted? Who knows. I'm no closer to knowing what the best tactics are, or if it makes any difference.

So by now I've lost interest and decided to play an FPS or something.

Friday, February 08, 2008

Name of the Game

I've been toying with the idea of changing the name of my game Nuclear Graveyard (again), since it has nothing to do with anything nuclear, and even less to do with graveyards. The reason I chose it was because I got a DynDns domain name, and I chose "ng" as the prefix to the standard domain "game-host.org". I chose NG as I was thinking of the phrase "network game", since at the time I didn't have any idea what I wanted to do with it! I then decided to give my new (at the time) game the initials "NG", and the rest is history.

I have toyed with the idea of giving it the ridiculous name "Space Nazis", just to see if it would perk up interest. However, this would be misleading as most people would expect some wacky platformer or something, whereas Nuclear Graveyard is a 3D multi-player "serious" strategy FPS game.

I might just change it back to its original name "Laser Squad 3D", since that sums it up perfectly if you remember the original Laser Squad game. I think it's a bit of a cliche to add "3D" to the end of a game's name though, which is why I changed it in the first place.

So, watch this space...

Thursday, January 31, 2008

A* Algorythm in Java - Download

I wrote this code a while ago, and I've finally got round to putting it here for public use. It's the A* path-finding algorythm, nicely self contained and ready for use. It can run in a thread if required, and to use it, you can simply write:-

AStar my_astar = new AStar(mymapclass);
WayPoints route = my_astar.findpath(start_x, start_y, end_x, end_y, b_run_in_thread);

Your
mymapclass must implement the IAStarMapInterface (included), which has 3 methods: getWidth(), getHeight() and isTraversable(). This tells the algorythm where it can and can't go. The class WayPoints is just an ArrayList of Points, giving the route.

I've used this code in all of my games (that require pathfinding) like Nuclear Graveyard and TremulousHulk.

(For those not in the know, the A* algorythm basically finds the closest path from one co-ordinate to another, taking into account blocked points.)

Monday, January 28, 2008

Tiny Web Server

There seems to be a durge (if that's the right word) of web servers called "Tiny Web Server", all vying to be the smallest web server. And now there's another one! I don't think it's the smallest, but it is a full web server for delivering static pages and documents.

It's written in Java, and the source comes to 23K. It should be pretty easy to extend to make it write dynamic web pages, so it should be ideal for starting your own web server project, or just giving you an idea of how web servers work. Or how not to write code. Take your pick.

It's available via SVN here. (That's svn://www.onlinegameplanner.co.uk/TinyWebServer).

Wednesday, January 16, 2008

Originality is a Curse

...That's probably why most games companies still churn out mostly FPS's and endless sequels to those FPS's.

I've written a game called Nuclear Graveyard which (IMHO) has a bit of originality: it's what I call pseudo-realtime. This means that rather than be proper realtime, it uses action points (e.g. walking forwards costs 1AP) but unlike most games that use APs, the player's APs are replenished automatically as both sides use them up.



Unfortunately, when most people play it, they don't seem to read the instructions, and assume that it's either a normal FPS ("why can't I move?") or a normal turn-based game ("How do I end my turn?"). I can't blame people for not reading instructions - who does? - but I've tried my best to make it self-explanatory, and included a tutorial, but to no avail. What do I do?

Friday, January 11, 2008

Multiple Platforms, Multiple Databases

SQL Enterprise Manager (or SQL Server Studio, as M$ like to keep changing the name) isn't a bad program, but obviously it only works with MS SQL, and only on Windows. Since I use MySQL, PostgreSQL, Oracle and MS SQL on Windows and Linux, I've been looking for a single program that can handle all of these databases, and I've found one: Aqua Data Studio.

It's written in Java (though there are other versions available) so it runs on Windows and Linux, and it easily connects to almost every kind of database, allowing you to do all the impotant things that SQL Server Studio does, like view the tables, edit the data, run queries etc...

I'm not affiliated with Aqua Fold in any way, but I thought I'd mention a program that is really useful and pretty good. It's free for personal use as well.

Wednesday, January 09, 2008

Domain Name Front Running

I wondered if any companies do this (i.e. you search for a domain with the intention of buying it, and the company that you use to search for it buys it up, knowing that you want it). And yes! Of course it happens...

Friday, January 04, 2008

My New Language

I have finally abandoned my attempt at a new Lisp-like language. I don't think I realised how hard it would be. Converting a text file of my new language into an AST (an active syntax tree) was the easy part. The hard part was storing variables (globals v locals, scope, identically named vars overriding each other, etc...) and calling functions (i.e. replacing the params in the function) among other things.

I should have planned it all better as I was also going round in circles with my language definition: I was changing it to fit one circumstance, but then forgetting why I'd done that, and then I'd change it back again to fit the original circumstance.

However, the final nail in the coffin was my thought "what am I going to do with it when I've finished?" It obviously had no IDE, barely any libraries, no debugging facilities, probably lots of bugs, and probably lots of flaws in the design. Why would I, never mind anyone else, choose to use it when there's plenty of other better languages out there?

Still, it's given me a new insight into how languages (might) work, and hopefully made me a better programmer. Now onto my next project: a mega-multithreaded program, where every little aspect has it's own thread. It's how the human body (i.e. cells) work (I think) so it must be a step in the right direction. And with all this talk of parallel programming, it can't do any harm for me to fail at that as well.

Thursday, December 13, 2007

Don't Buy Western Digital Hard Drives

More political posting I'm afraid...

Anyway, to get straight to the point, Western Digital HD's are crippled with DRM to prevent files with certain media extentions (e.g. AVI, MP3) from being shared across network drives. Even if they are your own creation! And the name of the software that does this? "WD Anywhere Access". You couldn't make it up!

Friday, December 07, 2007

My Programming Adventure - Is the journey nearly over?

I've alluded before to the fact that I sometimes think of my time spent programming as an adventure, looking for the reason why I program and what I hope to achieve. (I'm talking about my hobby programming of course - I do my profesional programming to pay the bills).

Several times I've been in the middle of writing one of my games, and suddently realised I'm not actually enjoying writing it. Or I've finished a game and realised it's not that much fun to play, or I think it is but the ROTW disagrees.

However, I have now found my holy grail. I've written a small, simple and (AFAIK) original puzzler called Chain Reaction. It's pretty addictive, but what has caused it to really take of here where I work is the high score table. People are falling over themselves to try and beat each other, and I'm loving the fact the people are telling me they hate the game because they're spending too much time playing it but they can't stop! I may be egotistical, but I think it's the kind of praise and recognition I've been looking for all these years.

Thursday, December 06, 2007

New Language Update

Here's a tip for anyone who's thinking about writing their own language - plan it first. I know I should have. I've got a reasonable understanding of how Lisp works (i.e. evaluate everything inside the brackets recursively, and then process it) but I made some silly mistakes...

..Like evaluating the brackets each time I read them. For example, the program:-

(defvar lst (quote 1 2 3) ; <- "lst" now contains (1 2 3), correct.
(print (lst)) ; Error! I've processed "lst", but the function "1" (i.e. the first item in the list) is (obviously) unknown!

This is just one example. I'm going to start again. I've learnt a lot from my mistakes though, and my aim is to have a language with the best Lisp features like Macros, but more practical with simple functions to connect to databases etc...

Thursday, November 29, 2007

My New Programming Language - "Harry".

Being a programmer who has no fear of programming a disaster, I've decided to write my own programming language.

"Madman!" I hear you cry, but no, seriously. And on the face of it, it's not that difficult. On the face of it, it's just a case of reading a text file and turning that into "symbols", which your interpreter/compiler converts into something existing, whether it's Bytecodes or good old machine code.

My language is called "Harry", and is similar to Lisp, since everyone seems to rave about it, and I've been quite impressed with it. However, there are a few (minor) problems with Lisp, which no doubt people will take me to task for. Here's my : it's not standard enough (there seem to be lots of variants), and it's not very practical (in order to do something like graphics or databases, you need to find libraries).

I've written the interpreter in Java for platform-independence. It's still in the development stage, so no download yet. The current problem I've got is functions and the variables contained within. What happens if a function names a variable with the same name as a global variable? And scope is a problem, i.e. "unsetting" the variable once the function has finished, so the global var becomes available. But what if the function calls another function? And recursion? And what about if a parameter to the function has the same name as a variable?

Anyway, to whet your appetite, here's an example of the code (which should be self-explanatory):

; Add, eq, print
(print (eq 2 (+ 1 1))) ; returns 1

; Set
(set lst (quote 1 2 3))

;quote, contains, if, return
(print (if (contains 2 lst)(ret true)(ret false))) ; prints "True";

Monday, November 19, 2007

Why Are Named Parameters Rare?

One of the things that seems common to most languages, even the supposedly better new ones, is the lack of "named parameters". Surely it must have come to the attention of most language designers that having a line like the following is ridiculous:-

// Do some stuff
int x = MyFunction(true, false, true, true);

Okay, it's probably bad programming practise to have something like this, but even a simpler line with just one boolean would be bad. What on earth does each parameter mean? The only way of finding out is to query the underlying function's code, but that defeats the object of having well named functions. I'm still surprised that having named parameters isn't in most modern languages. How much better is the next line:=

int x = MyFunction(foo:true, bar:false);

Here you can see, without having to browse the underlying function, what each parameter means. Okay, this is nothing earth-shattering that will lead to perfect code, but it has to be a step in the right direction.

Thursday, November 15, 2007

Eclipse and Subversion (Subclipse)

I've blogged before about using Subversion and Eclipse - if you haven't installed Subclipse then don't do it! However, I've discovered another problem and solution to Subclipse...

Even when Subclipse is installed, if you have seperate src and bin directories, the bin directory can confuse Subclipse, since Eclipse likes to effectively delete it and recreate it with each build. The solution to this (apart from adding the bin directory to your ignore list) is to not "Scrub output Folder when cleaning projects".