ShotEngine – all bullets in one place

29 01 2009

In the same way all units will be controlled in the same engine, the bullets fired by the units will be moved into their own engine and controlled from there. First let’s create a “blueprint” for the shots as well (yes an Interface).

package interfaces
{
	import units.AUnit;

	public interface IShot
	{
		// How will we check the collision? Is it a big radius or just a point check?
		function checkUnitCollision():IUnit;
		function checkStaticCollision():void;

		// What happens if the shot hits something (damage? explosions?)
		// returns TRUE if shot will be removed.
		function onUnitCollision(unit:AUnit):Boolean; 

		// What happens if the shot hits something static in the world (like a wall or other obstacle)
		// returns TRUE if shot will be removed.
		function onStaticCollision():Boolean;

		// update movement, rotation, scale, animation etc
		function transform():void;
	}
}

Now we’re getting used to the above view so with a little time looking at the code I believe that in the end you could tell me that the shots flying around (or behaving in other ways) will have a few basic functions that will be called apon. checkUnitCollision() checkStaticCollision() onUnitCollision()  onStaticCollision() and transform().  Good. I don’t even care about creating a real implemented class of this interface, instead I want to start with the whole shotEngine that will control all shots.

I think we will take this class in parts as it might contain a few new things to the new actionscript coder. First you can start with creating a new folder besides the rest of the folders and name it “engine“. And then create a new class starting like this:

package engine
{
	import interfaces.IShot;

	import units.AUnit;

	public class ShotEngine
	{

		static private var instance:ShotEngine
		private var aShots:Array

		// ************ SINGLETON CLASS *************
		public function ShotEngine()
		{
			init()
		}

		public static function getInstance():ShotEngine
		{
			if (ShotEngine.instance == null)
			{
				ShotEngine.instance = new ShotEngine();
			}
			return ShotEngine.instance;
		}

For you who are familiar with these kinds of Singleton-classes, skip this section. For you who is not:   “WHOOOOAA!!” WTF was that??

Above is my favourite code experience of the year (yes I’m new to this as well). I’ve always had problems with the whole capsulating thing when it comes to OOP as I just don’t get how people work with global variables. I always found myself coding in a small component class deep down in a hierachy tree and suddenly need an instance of a class that’s in a toal other place, unreachable for me. The quick, dirty solution back then was to make more and more variables public and static so I could reach them from wherever I wanted to in the project. Not that OOP’ish… right.

The wonderful solution is a class called a Singleton-class. With this type of class, you can create one and only one single instance. Whenever you try to create another one you will only recieve the same instance you created from the start and it will contain the same variables and data as that first instance has. If you look at the code above you will see that it has a function called getInstance()

To use a singleton class, ALWAYS call the getInstance() function to get the instance of the class. Never ever create a new instance using the constructorname. Always call getInstance(). This way you assure yourself that you will have only one single instance of the class and in this way you can have access to the same data and methods wherever you need in a project.

Another very important thing is that a lot of classes in a gameproject can only have one single instance! You maybe want to have only one gameengines running at the same time.Noramlly you want to use only one keyboard. Only one HUD? One highscorelist, one onlineLobby etc etc.  There are ways to control that the constructor cannot be directly called apon but I won’t bring that up here. Lets focus on our class instead. Continue….

        private function init()
        {
            aShots = new Array()
        }

        public function addShot(shot:IShot)
        {
            //Add a new shot into the shotlist
            aShots.push(shot);

            // code to put shot in the 3D scene will be implanted here

        }

        public function updateShots():void
        {
            var tempShot:IShot
            var tempUnit:AUnit
            var flagDelete:Boolean

            for (var i:int = aShots.length-1 ; i>-1 ; i--)
            {
                flagDelete = false    // reseting deleteflag.
                tempShot = aShots[i]

                // first make the shot move/rotate/animate/beam...
                tempShot.transform()

                // is it hitting anyone or anything?
                tempUnit = tempShot.checkUnitCollision()
                if (tempUnit != null)
                {
                    // returning 'TRUE' if that specific shot wants to remove itself on impact
                    flagDelete = tempShot.onUnitCollision(tempUnit);       
                }
                if (tempShot.checkStaticCollision()==true)
                {
                    // returning 'TRUE' if that specific shot wants to remove itself on impact
                    flagDelete = tempShot.onStaticCollision();
                }

                if (flagDelete == true)
                {
                    // code will be implanted here to remove the visual shot from the 3D scene
                    aShots.splice(i,1) // removing shot from the shot list.
                }
            }
        }
    }
}

This “engine” will handle all shots that are flying around on stage, update them, check if they hit things and then remove them on collision if they are coded that way( some shots, a lightingcloud for example, may not want to be removed on impact but draw damage over time as the unit stays in the cloud).
So, here you go. Another post without anything happening on the scene ;) remember, the more boring code we get done underneath, the faster the progress will get later on. Next post I promise we must create something visual. Like.. hmm, a gun?

Advertisements




The importance of being lazy!

29 01 2009

I will soon code a LOT, actually I’ve started already behind this scene but before I make it official and show it all to you I want to pull the breaks and look in the rear window so I got all of you with me. Why’s that? Because if you don’t get the structure that’s in my head, a big part of the next upcoming code will be just a copy and paste experience and you’ll probably learn nothing so let’s take a look and let me explain some things for you. (naah you’re all smart, I’m just repeating it to understand it myself!)

Lets start with an Image:

classstructure

If we start from the bottom we have actually already created some of these “components”. The interesting thing as that all the words down there but “MESH” starts with an ‘I’. It’s because we are focusing the Interface of that component. Creating an interface makes it so much easier to code a bigger project as I don’t have to worry about how many different “transformers” I need to make or how they will be implanted. I don’t even have to create fully functional classes. This is called to “code towards the interface”. For OOP-experienced coders this is basic material but somehow Actionscript has attracted a lot of designers into the coding world and haven’t until AS3 really faced this way of programming.

So, now lets say I create a lot of controllers, transformers, weapons and shots (which will be the physical ‘bullet’ fired from the gun) I can now extend the AUnit (abstract class) into a unique unit, eg. Defender and place one of each component types in there.

As AUnit now already have the public function transformUnit() and also checkCollisions() it means that I can have as many units on the scene as I want to, looking different, behaving differntly, is controlled differently but still will be exactly the same to handle for the main core engine. Eg. Lets create 3 different units:

var arUnits:Array = new Array()
var player:AUnit = new Defender()
var computer:AUnit = new Tank()
var LANgamer:AUnit = new Soldier()

arUnits.push(player)
arUnits.push(computer)
arUnits.push(LANgamer)

for each(tempUnit:AUnit in arUnits)
{
	tempUnit.transformUnit()
	tempUnit.checkCollisions()
}

This simple code above creates 3 different units but they are all typed AUnit (!) this means we can treat them exactly the same and loop through them but they will react differently depending on which components they have inside them. Great!  I don’t have to code a loop for each unit! I don’t have to code the management for each controller, nor for each weapon.  I just code how they will behave. Now that I feel that I’ve sorted this out a little more I will start working on those weapons and clean up the previous code so we can focus on the fun part in here.





And the game so far…

28 01 2009

Here is how far we’ve come on these first posts. Remember that a lot of our work has been about seting up a good foundation to easily built new units later on, so yes, it’s a lot of code for maybe not that much of a result so far, but still it works like that infamous charm :)
http://www.solodev.eu/archon2160/DefenderTest.html





Paint the paper

28 01 2009

My guess is that PV3D chose the word “paper” because the way to treat 3D objects is very much like folding paper in different ways. Even if a 3D-object in the end could look like a very solid rock it is built up with simple planes and triangles that is carefully bent and rotated (actually the building blocks gets smaller than that but let’s rest here for a while). The small sides (triangles) that are building up the world doesn’t even have two sides. If you are looking on the other side of a triangle you will actually see… nothing. Nothing at all! So to even create the simpliest sheet of paper you will need to create two planes and flip one and stick it to the other to make it look like in real life (have both a front and a back side).

Now, technically, Papervision have a lot to wish for when it comes to performance and no matter how amazing you might be codewise you won’t just be able to create detailed lifelike models because it will take you thousands and thousands of these triangles to fold and model the details of a reallife complex object. Here is where “texturing comes in”.

Instead of using all these resourcedemanding triangles to showcase something you can actually paint stuff right on the triangles. Say you want to create an orange. Instead of creating every single small bump on an orange you could just paint those bumps on an image and then ‘wrap’ this image around a more simple sphere still creating the illusion of an orange.

Now, I’ve started up creating a few of the models I want to use in my game. Below you will see my unit: “DEFENDER” – a smaller buggy-like car which later on will have a big ass cannon on the roof.

textures

To create such a model, you will need some kind of a 3D-program. I’ve been working with 3D Studio MAX for the last 10 years so that is choice of app. First of all you create the actual “folding” of the object. Placing all triangles where they should be, bending rotating and modelling out all planes will give you a model something like the untextured one above. The texture in the picture is what I draw on a regular image in Photoshop. Wrapping that image on the planes causes the textured model which gives an impression of a much more detailed model than it really is. Good textures are very very important to create a good looking game. Spend a lot of time on that!

If you are interested in special tutorials in modelling, texturing, UVW-mapping etc.. just give me a call and I’ll see what I can do. At the moment I just want to get my “defender” to be a part of the game. To use these kind of custom models you will have to save them into some format that PV3D recognizes like *.3ds or collada.  In this case I will save my model into the *.3ds format and use the inbuilt parser Max3DS in PV3D.

package
{
	import controllers.*;
	import flash.events.*;
	import interfaces.*;
	import org.papervision3d.events.FileLoadEvent;
	import org.papervision3d.lights.PointLight3D;
	import org.papervision3d.objects.DisplayObject3D;
	import org.papervision3d.objects.parsers.Max3DS;
	import org.papervision3d.view.BasicView;
	import transformers.*;
	import units.*;

	public class View3D extends BasicView
	{
		private var defender:AUnit
		private var defenderMesh:Max3DS
		private var light:PointLight3D

		public function View3D()
		{
			super();

			// set the camera in a nice position
			camera.y = 200
			camera.z = -1000
			camera.zoom = 90

			// place a light somewhere (just to get used to it, this one doesn't do much at the moment)
			light = new PointLight3D()
			light.x = 1000
			light.y = 5000
			light.z = -6000
			scene.addChild(light)

			startLoadMesh()

		}

		private function startLoadMesh()
		{
			// lets load our mesh
			defenderMesh = new Max3DS()
			defenderMesh.load("meshes/units/DefenderBody.3DS",null,"./meshes/units/")
			defenderMesh.addEventListener(FileLoadEvent.LOAD_COMPLETE,meshLoaded)
		}

		private function meshLoaded(e:Event)
		{
			// mesh has been loaded and is now put in as a parameter in this new object called Defender
			defender = new Defender(defenderMesh,new LocalController(),new CarTransform(7,0.85,0.3));
			scene.addChild(defender)

			// startRendering() must be called for the 3D-engine to actually start drawing each frame
			this.startRendering()

			// each time the 3Dengine redraws the screen, onFrameTick is called.
			this.addEventListener(Event.ENTER_FRAME,onFrameTick)
		}

		private function onFrameTick(e:Event)
		{
			// lets transform the unit due to the control-data it recieves.
			defender.transformUnit()
		}
	}
}

The code above actually loads my mesh and adds it on the scene in 3D. Not only that, the mesh is passed into my new class: Defender.as which is extended from AUnit so now FINALLY the chain is connected and I got a unit that do have a mesh, a control component and a transform component. I got my first primitive unit driving around on the scene!! Well.. almost, I just need to create that Defender class..

package units
{
	import interfaces.*;
	import org.papervision3d.objects.DisplayObject3D;

	public class Defender extends AUnit
	{
		public function Ball(mesh:DisplayObject3D,controller:IUnitController,transformer:ITransformer)
		{

			super(mesh,controller,transformer,0);
		}

	}
}

We need no more than that to create our unit. Remember now that we can create as many different components as we want to. Just combine them, reuse them and experiment with them to create new units.





Papervision3D – an introduction to the 3D world.

27 01 2009

Ok, lets take a small break from the game creating. I assume you already know about Flash and AS3 but if you haven’t worked with 3D programming before it would be good with some foundational theory.  Let’s start with the dimensions (no, kidding! a third??)

coordinatesystems

As you can see by the figures the 3D coordinate system differs in many aspects. First of all, there is a third axis showing the depth of the image. Imagine the screen as the 2D image a normal FlashMovie can project. Now think of the Z-axis as if you could put in your hand in the screen and push that movie further away or drag it closer to you. The movie would then move on the Z-axis. (I know this is not the whole truth but will you please pretend for a while, ok?)

Now, something is new with the other “normal” ones as well. It seems like the origo (0,0) has moved away from being in the topleft corner to the absolute middle of the screen. Ok, fair enough, so as soon as you want things to move to the left of the screen you will set the X-value negative. The last thing that might be easy to forget for you “Flashers” is that Y-axis is now pointing upwards meaning that negative values are below the 0,0,0 (origo). So whenever you want something to move upwards you increase the Y-axis.

There are many ways to use this 3D space but in my game I will look at the 3Dworld as if Y is the altitude of everything meaning that the flat arena we will create and all the units moving around will mostly be stretching out and move through the X and the Z-axis.

Today I will not dive deeper into 3D and how the models are built up rather then just present the core objects that are needed to even display something in 3D. Lets begin:

Viewport

There is no real 3D. You know that, right? I mean, we’re only simulating a 3D environment but in the end it will be projected on a 2D surface (the screen). The viewport is exactly that. It’s the 2D area where all this simulating will take place. For now, just think of it as a small rectangular MovieClip that you will just add to the displaylist just as normal. It’s what will be within this rectangle that is the cool stuff.

Camera

A camera is nothing else but your eyes in the 3D world. Think of it as an object in this 3D environment I just explained above that could move around in all axis and also rotate around. Wherever it is located, from that angle all objects in the scene will be projected.  The projected image will be visible in the Viewport explained above. (aaaah so the camera is the camera, and the viewport is like the TV showing whats catched be the camera?? … yes)

DisplayObjects3D

Now this is the objects that will be visible in the 3D-world. Damn, you know this already. It’s just like using DisplayObjects in flash. Actually, the PV3D team has worked hard for you to be as comfortable with this new technique giving you almost the same methods to work with 3D as with 2D. Want to add a DisplayObject3D in the scene?  use addChild(). Want to move it to the right?   Increase the X parameter. It’s that simple :)

Also, while we at it. DO3D is very much a container just like it’s cousins DisplayObjectContainers. This means that you can put other DO3D’s into other DO3D’s just like you would add a Sprite into a MovieClip etc. Works like a charm (because charms work, right?)

Light

Now this one is somehow new to some of you 2Dguys. Creating 3D projections is a lot about fooling the eye and mind with small tricks just to come closer to the “real thing” and what we expect to see in a 3D environment. One crucial thing that adds to the illusion of depth is light. If all sides of a green shape were litten equally, the viewer have a really hard time both getting the feeling of 3D-depth and to make out the correct form of that shape. See the image below:

lightsource1

We will work with PointLights (Pointlight3d) that as the word hints is a light placed in a point in the world. This means that you will be able to move that light just as you move objects and cameras around. With a good light you can enhance a 3D-environment to extreme standards!

Now that you are introduced to the basic components of a 3D-world, lets start the engines up and create our first bad ass scene!

First, lets create a FLA. Just create a new AS3 FLA in Flash and set the document class to ‘Main’

Now let’s create our Main.as   class and make it as simple as possible. I’ve always liked to keep the document class as clean as possible and as soon as it gets cluttery I move most of the code into a new class, cleaning Main up again.

package {

	public class Main extends Sprite
	{
		private var view:View3D

		public function Main()
		{
			view = new View3D()
			addChild(view)
		}
	}
}

View3D will be our class with all fancy 3Dstuff. To make it very (VERY) simple I will now extend a class called ‘BasicView’ and turn it into my View3D.as . Basicview’s only purpose is to take one viewport and one camera and put it all in one scene so that you are ready to go immediatly. Let’s have a look at it:

package
{

	import org.papervision3d.lights.PointLight3D;
	import org.papervision3d.view.BasicView;

	public class View3D extends BasicView
	{
		private var light:PointLight3D

		public function View3D()
		{
			super();
			createSomeObjectsOnTheScene()
			this.startRendering()
		}

		public function createSomeObjectsOnTheScene()
		{
			light = new PointLight3D()
			light.x = 1000
			light.y = 5000
			light.z = -6000
			scene.addChild(light)
			var tSphere:Sphere = new Sphere()
			scene.addChild(tSphere)
			}
		}
	}
}

Now let me take you through what just happened. First when View3D is created, I call super() meaning I call the BasicView constructor. BasicView class creates a ‘scene’ and puts a ‘camera’ on that scene. It also places the camera on z:-1000 so that it can view all objects from a fair distance (camera is by default “looking” towards 0,0,0). I then call my own function ‘createSomeObjectsOnTheScene’ where I first create a light and locates it somewhere fairly random. In the end I create the first really visible object and puts it in the displaylist using addChild. As i don’t locate it somewhere it will be placed on 0,0,0 (where camera is looking). taddaaa… but when running you will find the sphere looking kind of .. wireframed. Yes, and thats actually the correct term for that look as well.
It is as simple as if you havent specified HOW the surface will look on the sphere it will draw it in wireframe mode (as a sign of not having any material wrapped around itself. Tomorrow I’ll show you how to set some materials and then we will also head back to the game. Otherwise I will never be able to finish it!





And so the coding begins!

27 01 2009

I’ve sat down now and structured up some of my thoughts into basic Interfaces but to be able to visually organize everything I start up with setting up a little folder structure. Just like this:

folderstructure

I will be using Flex 3 as my IDE so some future screens will probably showcase that environment. If you do not know how to set up a Papervision project in Flex 3 this site is actually not the right one to find the answers in. I’ve seen plenty of great tutorials out there so I won’t dive into that here.

As you can see a lot more folders and structures will be needed later on but his will be perfect for the start I intend to write.  I know you are all eager to begin setting up a scene with Papervision but I actually will first create a few small classes first that will make it easier for me to explain how the units (as I will call all combat vehicles from now on) will behave. Let’s actually start with something as weird as the game controllers (!)

package interfaces
{
	// this is the Interface for all controllers, be it local, ai or remote via multiplayer.

	public interface IUnitController
	{
		// each Controller gives away a ControlMatrix-object containing at least the following parameters:
		// horizontal: , vertical: , newLastPosition:   if true then these values are used: , posX:, posY:, rotation:
		function getControl():Object
	}
}

I want to make sure that the network gaming will be a part of all planning from start and this is a great way to do that. Above is an interface that will make all controllers to behave in the same way. To show you a normal implementation of this interface, lets create a normal, local controller.

package controllers
{
	import flash.ui.Keyboard;
	import se.xcom.input.ArcadeKeyboard;
	import interfaces.IUnitController

	public class LocalController implements interfaces.IUnitController
	{
		private var key:ArcadeKeyboard
		public function LocalController()
		{
			key = new ArcadeKeyboard(Main.scope)
		}

		public function getControl():Object
		{
			var tVert:Number=0
			var tHoriz:Number=0

			if (key.isDown(Keyboard.UP))
			{
				tVert++
			}
			if (key.isDown(Keyboard.DOWN))
			{
				tVert--
			}
			if (key.isDown(Keyboard.LEFT))
			{
				tHoriz--
			}
			if (key.isDown(Keyboard.RIGHT))
			{
				tHoriz++
			}
			var Ob:Object = {vertical:tVert,horizontal:tHoriz,newLastPosition:false}
			return Ob;
		}

	}
}

This little class over here checks whether the arrowkeys has been pressed. Instead of sending a true for each direction, this class actually creates a Vertical axis where UP becomes +1 and DOWN becomes -1. On the Horizontal axis RIGHT becomes +1 meanwhile LEFT returns -1. I will later on show you how this can be useful in such arcade game. Also I’ve used a custom keyboard-class called ArcadeKeyboard that I created a while ago as AS3 does no longer contain the useful “isDown” features that AS2 had.  I’ve temporarly packed this class + a degreeconverter down for download here if someone would find it useful.

Now, let’s create a temporary Unit file just to see if we can control it with our controllers. But first I want to set up a decent Interface for our units as there are functions that all units to perform, eg. moving around, checking for collisions, attacking etc. For now, let us create this interface:

package interfaces
{
	public interface IUnit
	{
		function transformUnit():void
		function checkCollisions():void
	}
}

What this small interface just tells us is that: Every single unit that is even trying to implant me must have a transformUnit function and a checkcollision function. Sweet! But we will not stop there this time. We KNOW that all units will behave in a certain way when it comes to movement and collisioncheck. We also already know that each unit will be a DisplayObject3D (Papervisions own piece of DisplayObject), that each unit will carry a badass gun etc etc. So why create all this code over and over again for all units? Let us create an abstract class! You don’t know what that is? heck.. I’m just starting to learn myself, but to make it simple: an abstract class is a class that will never be instantiated on it’s own as it only contains parts of the code. That part is the code that is similar to ALL classes that will extend from that abstract class.

This is not supposed to be a lesson in OOP, but if you find the upcoming things weird and stupid I suggest you to find some tutorials or books that will cover the basics of OOP-programming, inheritance and design patterns as it will totally change your way of coding.  Now let’s get to business and maybe things will clear out a bit:

package units
{

	import interfaces.*;
	import org.papervision3d.objects.DisplayObject3D;

	public class AUnit extends DisplayObject3D implements IUnit
	{
		private var mesh:DisplayObject3D
		private var control:IUnitController
		private var transformer:ITransformer
		private var unitId:uint

		public function AUnit(mesh:DisplayObject3D, control:IUnitController,transformer:ITransformer, id:uint)
		{
			this.unitId = id
			this.mesh = mesh
			this.transformer = transformer
			this.control = control
			this.addChild(mesh)
		}

		public function transformUnit():void
		{
			// move and rotate the object due to the transformer.
			transformer.transform(mesh,control.getControl())
		}

		public function checkCollisions():void
		{
			// abstract , must be implanted later on!
		}
	}
}

Ok, lets see what we have now. This is an abstract class that will be the foundation of all Units hereafter. To create a unit we must therefor pass in a 3D-model (which I from now on will call meshes), we must also pass in a control which we alread happened to have created one. Good.
Then there is a new strange thing which I now call a Transformer. This is the component that will lie BETWEEN the unit and the controller. So from the controller comes data which buttons has been pressed (sort of). Now this TRANSFORMER turns that data into something visually splendid like moving the unit forward, rotating it, making it roll, float or shrink…
So even if we have the same controller for every unit they units might behave differenly as they have different transformers connected to them. Sounds intruiging, ey? Let’s create a transformer. After that I think we are ready to actually see something visual in 3D :)

package interfaces
{
	import org.papervision3d.objects.DisplayObject3D;

	public interface ITransformer
	{
		function transform(mesh:DisplayObject3D,control:Object):void;
	}
}

Each Transformerclass is now forced to have the function “transform” in them and also do they need to pass the parameters ‘mesh’ and ‘control’. Good, thats all we need! Let’s for starters make a simple Car-transform class (making the unit behave just like a car when controlled).

package transformers
{
	import interfaces.ITransformer;
	import org.papervision3d.objects.DisplayObject3D;
	import se.xcom.math.Degrees;	

	public class CarTransform implements ITransformer
	{
		// simple carsteering with no skid

		private var speed:Number	// current speed
		private var acc:Number		// accelerating force
		private var moveFric:Number // friction force (0 - 1.0)
		private var rotSpeed:Number // turning speed

		public function CarTransform(acc:Number, movementFriction:Number, rotSpeed:Number)
		{
			// setting up simple physics variables
			this.acc = acc
			this.moveFric = movementFriction
			this.rotSpeed = rotSpeed
			reset()
		}

		public function reset():void
		{
			speed = 0
		}

// now heres that most important part where the mesh will be transformed using the data from the controller.
		public function transform(mesh:DisplayObject3D, control:Object):void
		{
			// movement
			speed += control.vertical*acc
			speed *=moveFric
			mesh.x += Degrees.dCos(mesh.rotationY)*speed
			mesh.z -= Degrees.dSin(mesh.rotationY)*speed

			// rotation
			mesh.rotationY += rotSpeed*speed*control.horizontal
		}

	}
}

You wonder what that weird Degree class is? Well let’s put it like this. I’m selflearned in every way. I have not studied programming, nor game design and definitely not Math. So when the inbuilt Math class decides to use radians instead of degrees (which all displayobjects are using when rotating) I decided to create a simple class that lets you use Cos and Sin with degrees. There you go. If you’re a mathohman, please convert it to whatever you like. If you are like me, you can find the class with the other ArcadeKeboard class here.

Damn! This is becoming a huge post. I know we haven’t even compiled the code once yet and we got nothing to show so far but underneath the surface something really nice is about to happen. I stop his post right here and will soon be in again with our first 3D visuals. Yes I promise! Next time it’s time to dive into Papervision’s wonderful sea (space?)





The challenge of creating a game without writing a single line of code

26 01 2009

If you’re new to OOP (which I still do consider myself to be) words like Interfaces, Abstract classes and Polymorphism might sound pretty intimidating, but trust me, it will make your life so much easier (no your private life, don’t mix polymorphism into that!). 3 years ago when I started up this project and coded in a very simple 3d environment (Blitz3D) I coded in classical functionbased way. Using a lot of codefiles and structured foldersystems worked but for each playerunit that was added the code got heavier to support and bugfix. The big catastrophy happened when I decided to look at networking and multiplayer parts.

The whole static code for each unit needed to be rewritten to allow smooth multiplayer communication. And so the project came to a halt.

Now how can we prevent this?? Well, at least we can make it much easier to support and change in code without the whole project is falling apart by using these nice OOP features and design patterns. Even if it also will mean some extra code for startes it will mean a lot LESS code by the end of the project as we will be able to reuse a lot of the code.

Now here is my challenge:

screen3

The actual game (stripped from multiplayer lobby, scoreboards, rankingsystems, boardmode etc) is a simple 2p fast paced game where the players control one unique unit chosen from 10 different units. They will drive, fly and roll around on an battlearena trying to kill each other with different types of weaponarsenal. Each type of unit will have different ways of control, transport, behaviour and weaponry. AND there will be networkcode! The game will be in 3D but the units themselves will be controlled on the flat arena surface (for now) which means that we can actually start creating this game as a 2D game until visuals will be an issue.

The first thing that pops up in my head is: components!

Yes, of course. If I just could have a general unit with actually no things mounted at all on it we could just add what is needed to create a unique unit. Say we add some way of transportation (wheels? wings? teleporter?). We also need some control system to use the transportation with. Then we add some kind of weaponry. To the weaponry we need ammo (as this could actually be different to one single gun). At last we could add a “black box” containing data about damage and such which could be useful in such a game.

Without really creating any useful code that does something, we at least have a structure of the units we will play around with. Using my small pieces of papers I could write down something like this:

UNIT

  • Controller
  • Transportation
  • Gun
  1. —– Ammo
  • BlackBox

Now we have a great foundation to create as many different combat units that we want to, structured in a meaningful way. All we need is to have some kind of engine to take each unit and go through these components step by step and give them the same general command.

Eg. Engine takes the first unit, a tank. First checks controller if any button been pressed, then it checks the transportation and uses the data it got previously to steer the tank in a “tankish” way. Finally it checks wether a gun has been fired and if thats the case it uses the weaponcomponent to fire away a bullet of the Ammo-type.

The same procedure will be used wether it be a single soldier, an aircraft, a laserbeam or guided missiles. Time to get it into code… stay tuned!