Special Effects

8 02 2009

This is one of the last core parts of the game, at least when it comes to the Arenafighting (we got a lot of lobby, networking and boardgame to take care of). This is also one of the best parts as we will be able to handle explosions, lightnings, sparkles and other effects. I have decided to create an EffectEngine similar to the ShotEngine but to tweak it and keep it a little more open as effects will probably act and look very different depending on the effect we want to create.

First, as usual, I start with an Interface:

package interfaces
{
	public interface IEffect
	{
		function update():void
		function updateDying():void
		function remove():void
	}
}

As you can see, the effects will not have many common functions, but the ones they have, the EffectEngine will use. Let’s build an abstract class of the Effects, using the Interface we just made:

package effects
{
	import interfaces.IEffect;

	// abstract
	public class AEffect implements IEffect
	{
		public var life:int
		public var flag_Dying:Boolean
		public var flag_Dead:Boolean

		public function AEffect(life:int)
		{
			this.life = life
			flag_Dying = false
			flag_Dead = false
		}

		public function update():void
		{
			// here the effect will be updated each frametick
		}

		public function updateDying():void
		{
			// if flag_Dying==true , update with this function
			// instead of the normal update()
			// this is to be able to smoothly remove effects
			// when they are done
		}

		public function remove():void
		{
			// when updateDying is done (flag_Dead==true), remove effect
		}

	}
}

The only thing we add in this abstract class is 3 variables. time is the time the effect will be visible in millisecs. Now we are ready to create our EffectEngine.

package engine
{
	import effects.AEffect;
	import managers.Time;

	public class EffectEngine
	{

		static private var instance:EffectEngine
		private var aEffects:Array

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

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

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

		public function addEffect(effect:AEffect)
		{
			//Add a new effect into the effectlist
			aEffects.push(effect);

			// different from the other engines, the effects
			// has their own addChild procedure as they looke very
			// different to each other.
		}

		public function updateEffects():void
		{
			var tempEffect:AEffect
			var flagDelete:Boolean

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

				if (tempEffect.flag_Dying == false)
				{
					// if effect is alive and kicking!
					tempEffect.update()
					if (tempEffect.life < 0)
					{
						tempEffect.flag_Dying = true
					}
					tempEffect.life -= Time.getInstance().timeElapsed
				}
				else
				{
					// if effect is about to die out
					tempEffect.updateDying()
					if (tempEffect.flag_Dead == true)
					{
						tempEffect.remove()
						flagDelete = true
					}
				}

				if (flagDelete == true)
				{
					trace("Removing effect from list")
					aEffects.splice(i,1) // removing shot from the shot list.
				}
			}
		}
	}
}&#91;/sourcecode&#93;

As usual, it is a Singleton-class preventing several instances of EffectsEngine being created. Also, The normal 'add' function is there just like the shotEngine. Biggest difference is in the updateEffects() function, hopefully it is explaining itself. The procedure of an effect is this:
First it gets created and then immediatly added to the EffectEngine.
The effect updates itself using update() until 'life' has reached 0.
Then the effect update the updateDying() instead until , flag_Dead == true
Last the effect is removed from the list and is running the function remove().

Now I will create two effects that will need some kind of explanation. One Explosion (that is actually two effects in one, I'll explain later) and one BombDust that will dust up the arenaground where the explosion has been.
Let's start with the Explosion :) Here is my visual idea of creating it:

<img class="alignnone size-full wp-image-215" title="explosion" src="https://papergem.files.wordpress.com/2009/02/explosion.jpg" alt="explosion" width="510" height="250" />

I will use two planes. One that is aligned to the ground giving a lightEffect on the ground, and one that is a "billboard". A Billboard is a plane that is always facing the camera, no matter where the camera is placed. The Billboard will have an animated movieclip where I use an explosion I rendered in 3DSMax. The groundaligned plane will just have a BitmapMaterial with an image I created in Photoshop. I will scale this image back and forth to simulate an intensity increase and decrease of the explosion.

One important thing I want to stress right now before we get to coding is that png and alpha-channels doesn't match good with performance and optimization. In some projects it is very convinient to use alpha-channels and transparency but when creating a PV3D-game you will immediatly choke the system with more than a few alphatransparencies on the screen.

My solution to this is to use the blendmode ADD. ADD 'adds' it's RGB values to the normal RGB-values giving a "lighter" effect whereever the RGB is more than 0,0,0. If you didn't catch that just remember this: Whatever on the image you don't want to impact the screen, use 0,0,0. Hmm I maybe should show you the images instead:

<img class="alignnone size-full wp-image-216" title="explosionground1" src="https://papergem.files.wordpress.com/2009/02/explosionground1.jpg" alt="explosionground1" width="90" height="89" /><img class="alignnone size-full wp-image-217" title="010" src="https://papergem.files.wordpress.com/2009/02/010.jpg" alt="010" width="128" height="128" />

Wherever it is black, it will be invisible. The brighter the rgb is, the more it will lighten up the actual screen, AND most important, this is a faster way to create lighteffects with than using alphachannels, transparency and png's. Let's look at our implementation of the Explosion.

package effects
{
    import flash.display.BlendMode;
    import managers.Layers;
    import org.papervision3d.materials.BitmapMaterial;
    import org.papervision3d.materials.MovieMaterial;
    import org.papervision3d.objects.primitives.Plane;
    import org.papervision3d.view.layer.ViewportLayer;
    import se.xcom.math.Degrees;

    public class Explosion extends AEffect
    {
        private static var layerIndex:int = 1
        private var airExp:Plane
        private var groundExp:Plane
        private var groundCount:int
        private var layerAir:ViewportLayer
        private var layerGround:ViewportLayer

        public function Explosion(posX:Number,posY:Number, posZ:Number)
        {
            super(1100);
            init(posX,posY,posZ)
        }

        private function init(posX:Number,posY:Number,posZ:Number)
        {
        // create round sphere explosion in air
            var expMat:MovieMaterial = new MovieMaterial(new mcExplosion1(),false,true)
            airExp = new Plane(expMat,1000,1000)
            airExp.x = posX
            airExp.y = posY
            airExp.z = posZ
            airExp.lookAt(View3D.scope.camera)

            layerAir = new ViewportLayer(View3D.scope.viewport,airExp)
            layerAir.blendMode = BlendMode.ADD
            layerAir.layerIndex = layerIndex
            Layers.EFFECTAIR.addLayer(layerAir)

        // create the explosionlight on ground
            var groundMat:BitmapMaterial = new BitmapMaterial(new bmpGroundExplosion1(0,0))
            groundExp = new Plane (groundMat,600,600)
            groundExp.x = posX
            groundExp.y = 0
            groundExp.z = posZ
            groundExp.rotationX = 90

            layerGround = new ViewportLayer(View3D.scope.viewport,groundExp)
            layerGround.blendMode = BlendMode.ADD
            layerGround.layerIndex = layerIndex++
            Layers.EFFECTGROUND_EXP.addLayer(layerGround)

            View3D.scope.scene.addChild(airExp)
            View3D.scope.scene.addChild(groundExp)

        }

        override public function update():void
        {
            airExp.lookAt(View3D.scope.camera)
            airExp.pitch(180)

            groundExp.scaleX = 1+Degrees.dSin(groundCount)*1
            groundExp.scaleY = 1+Degrees.dSin(groundCount)*1
            groundCount += 10
        } 

        override public function updateDying():void
        {
            this.flag_Dead = true
        }

        override public function remove():void
        {
            View3D.scope.scene.removeChild(airExp)
            View3D.scope.scene.removeChild(groundExp)
            Layers.EFFECTAIR.removeLayer(layerAir)
            Layers.EFFECTGROUND_EXP.removeLayer(layerGround)

        }

    }
}

Some explanation here is needed. In my Layers.as class I have created a lot of different layers and put them in a, in my opinion, good indexed order. Now if I just put my objects directly in one of those layers I would get a very strange effect where two explosions would be drawn upon each other like transparent squares. I want the light of the effects to blend with each other if several explosions are on the screen and that is why I put every object in a single unique layer, put the correct blendmode on them and finally put those layers on the parent layer in Layers.as
Yes it could take some time to get your head around, but hey, it works. This is this typical thing that is hard to explain unless you’ve been there yourself.
Well! The explosion now works! This one doesn’t have any long fading when it’s time to “die” but is removed immediatly.

As we’re on it, let’s create a simpler effect, the BombDust.as

package effects
{
	import flash.display.BlendMode;

	import managers.Layers;

	import org.papervision3d.materials.BitmapMaterial;
	import org.papervision3d.objects.primitives.Plane;
	import org.papervision3d.view.layer.ViewportLayer;

	public class BombDust extends AEffect
	{
		private static var layerIndex:int = 1
		private var layer:ViewportLayer
		private var airExp:Plane
		private var dust:Plane
		private var groundCount:int

		public function BombDust(posX:Number,posZ:Number)
		{
			super(8000);
			init(posX,posZ)
		}

		private function init(posX:Number,posZ:Number)
		{
		// create dustPlane
			var dustMat:BitmapMaterial = new BitmapMaterial(new bmpBombDust(0,0))
			dust = new Plane (dustMat,600,600)
			dust.x = posX
			dust.y = 0
			dust.z = posZ
			dust.rotationX = 90
			layer = new ViewportLayer(View3D.scope.viewport,dust)
			layer.blendMode = BlendMode.MULTIPLY
			layer.layerIndex = layerIndex++
			Layers.EFFECTGROUND_DUST.addLayer(layer)
			View3D.scope.scene.addChild(dust)
		}

		override public function updateDying():void
		{
			this.flag_Dead = true
		}

		override public function remove():void
		{
			View3D.scope.scene.removeChild(dust)
			Layers.EFFECTGROUND_DUST.removeLayer(layer)
		}
	}
}

Instead of the ADD-blenmode, this one uses the MULTIPLY, darkening the area instead of brighten it up.
bombdust

Now its just a few lines of code that must be implanted in the GrenadeClass just to spawn these effects whenever the grenade explodes.

override public function killByAge():void
        {
            var exp:Explosion = new Explosion(this.x,this.y,this.z)
            var dust:BombDust = new BombDust(this.x,this.z)

            EffectEngine.getInstance().addEffect(exp)
            EffectEngine.getInstance().addEffect(dust)
        }

Try out the link at the new page above (yes in the menu, called Archon2160). If you’re lucky, there might be a build there where you can see how the effects are triggered. Have fun and hope you learn something. I always do!

Advertisements




Adding Guns and Explosives

7 02 2009

It’s been a while since I wrote about the game in here and as I’ve previously mentioned, I will not cover every single line of code in this blog.

The simple reason is that I would have no time left for developing Archon2160 if I were to comment every adjustment of the previous classes and additions of small elementary things. Instead I will try to focus of the problems I face and how I solve them, trying to be as tutorial-based and educative as possible.

Now, I promised guns and bullets long ago and what would an action game be without that? Previously I created that ShotEngine.as class taking care of every single lethal object, but as usual it has been slightly modified. Today it looks 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;
		}

		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
			// this is just temporary ugly code
			View3D.scope.scene.addChild(shot)

		}

		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.transformMesh()

				// 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();
				}

				// checks if the bullet/shot has been on the scene for too long.
				// good for exploding shots or bullets that's been flying out of view.
				// has the life run out?
				if (tempShot.isOld())
				{
					// call the new IShot function
					tempShot.killByAge()
					flagDelete = true
				}

				if (flagDelete == true)
				{
					trace("removed!")
					// code will be implanted here to remove the visual shot from the 3D scene
					// this is temporary ugly code
					View3D.scope.scene.removeChild(tempShot)
					aShots.splice(i,1) // removing shot from the shot list.
				}
			}
		}
	}
}

Newest additions is that AShot now recieved a “lifeTime” that decreases for each frame. When it’s less than zero (0) the shot will be taken out of the scene and the ShotList. I will use this function both for deleting shots that has gone out of view for a while and for timeTriggered explosives (like the grenade I am about to show you). When time run out… BOOOM!
So, let’s look at our first real shot then! It’s a grenade :)

package shots
{
	import engine.UnitList;

	import managers.MeshConstants;
	import managers.Time;

	import org.papervision3d.objects.DisplayObject3D;

	import se.xcom.framework.managers.MeshManager;
	import se.xcom.math.Degrees;

	import units.AUnit;

	public class Grenade extends AShot
	{
		private const speed:Number = 90
		private const grav:Number = 8
		private var speedX:Number
		private var speedY:Number
		private var speedZ:Number
		private var rotX:Number
		private var rotY:Number

		public function Grenade(pitch:Number, yaw:Number, id:uint)
		{
			var tMesh:DisplayObject3D = initMesh()

			// number 1300 is the lifeTime of the grenade.
			super(tMesh,1300,40,id,false)

			setSpeed(pitch,yaw)	

		}

		private function setSpeed(pitch:Number, yaw:Number)
		{
			// here all calculations take place to see at which direction the
			// grenade should go and how high the angle should be.
			// also sets a random rotation to the grenade.

			// pitch = rotating along X-axis
			// yaw = rotation along Y-axis
			speedY = Degrees.dSin(pitch)*speed
			var tempSpeed:Number = Degrees.dCos(pitch)*speed
			speedX = Degrees.dCos(yaw)*tempSpeed
			speedZ = -Degrees.dSin(yaw)*tempSpeed
			rotX = Math.random()*40-20
			rotY = Math.random()*40-20 

		}

		override public function checkUnitCollision():AUnit
		{
			var aUnits:Array = UnitList.getInstance().units
			for each (var tUnit:AUnit in aUnits)
			{
				if (tUnit.mesh.distanceTo(this) < this.csRadius+tUnit.csRadius && tUnit.unitId != this.unitId)
				{
					trace("BOOOM!!")
					return UnitList.getInstance().units&#91;1&#93;
				}
				return null
			}

			return null;
		}

		override public function checkStaticCollision():void
		{
		}

		override public function onUnitCollision(unit:AUnit):Boolean
		{
			return true;
		}

		override public function onStaticCollision():Boolean
		{
			return false;
		}

		override public function transformMesh():void
		{
			/*
			here is our first real use of the DELTA-TIMING I wrote
			about in my previous article. This grenade will move in
			exactly the same speed regardless of the framerate of the
			computer.
			*/

			var delta:Number = Time.DELTA

			// move the Grenade
			this.x +=speedX*delta
			this.y +=speedY*delta
			this.z +=speedZ*delta

			// rotate it
			this.yaw(rotX*delta)
			this.pitch(rotY*delta)

			// check Y boundary
			// if grenade hits the floor. Bounce upwards
			if (this.y < 0)
			{
				this.y = 0
				speedY = -speedY
			}

			// set fake gravity
			speedY -= grav*delta

		}

		private function initMesh():DisplayObject3D
		{
			/* 	here I am putting the grenade into another DisplayObject3D
				and slightly adjusting it's x-position. Later when I rotate
				the wholeMesh, the grenade will "wobble" as it is not placed
				exactly in the center. Not a big thing but it's a nice little
				detail giving some character to the grenade.
			*/

			var wholeMesh:DisplayObject3D = new DisplayObject3D()
			var tMan:MeshManager = MeshManager.getInstance()
			var mBody:DisplayObject3D = tMan.getMesh(MeshConstants.NADE)
			mBody.scale = 70
			mBody.x = -40
			wholeMesh.addChild(mBody)

			return wholeMesh;
		}
	}
}
&#91;/sourcecode&#93;

I have now also put a mouseButton parameter into the controls so now I can actually drive the Defender, move the cannon up and down and fire a grenade that bounces on the ground that after a while EXPLODES!!  ... well no not yet. It just traces "boom" and gets removed from the screen and from the ShotList.
<h4>Several instances of the same object</h4>
During the implementation and testing of the grenade I stumbled over the problem of using several meshes using the same original model. Firing one grenade worked just fine but as soon as I pressed fire again I either got an errormessage because I tried to add the mesh on the scene when it was already added or I got the effect of the first grenade disappearing and spawning by the gun again. All this just because I was using the same DO3D for all grenades.

So how do we avoid this? Well, if we know for sure that we will not alter the geometrydata of the object in any way, we can use the same geometrydata to create several "instances" of the DO3D. Having a quick look, not at the documentation but checking the class as of DisplayObject3D you will find a function called <strong>COPY()</strong>. It actually copys the geometrydata into a new DO3D so we can instead of taking our originalmesh to the scene, we copy the geometry to a DO3D and use that instead. There are two problems to solve though...

<strong>Problem 1: </strong>Using parsed meshes just like *.3ds or *.dae creates a DO3D and puts all models in there that also got their own DO3D's. So the first actual DO3D that you control as your mesh is just a container for another DO3D inside. Now this has worked so far but now that we need to recieve the geometrydata fo the 3DS we need to get our hands of that DO3D-child. Somehow for some hightech reason beyond me, you cannot just take it. You will need to know it's name<strong> (!)</strong>

So even if you know that the child is in there there is only one function to get it and that is DO3D.getChildByName() ... damn. One quick solution to this is to trace out the DO3D.childrenList() string and then see the name and after that code: DO3D.getChildByName(nameTraced) this does somehow seem pretty unconvinient because we don't at this stage have a clue how many meshes we will need to do this for and it somehow is considered ugly code with this hardcoded names if you later on would like to change the model of your meshes.

<strong>Here's my solution:</strong>


			var mesh:DisplayObject3D = parsedMesh
			// getting first child name
			var nameOfChild:String = String(mesh.childrenList()).substring(0,String(mesh.childrenList()).indexOf(":"))
			// extracting child
			var newMesh:DisplayObject3D = mesh.getChildByName(nameOfChild)

Without knowing the name of the child you can now retrieve it. Remember that this only works if the containerObject only contains one single mesh.

If not, the above code will only grab the first object.
Problem 2: When importing different meshes using different parsers the models comes from very different 3D-environments. One typical thing is that there is a difference in what actually is up/down, left/right and in/out. Some uses the idea of letting Y becoming the in/out depth meanwhile Z s going up and down. This is often handled by the parser turing it so it looks “correct” in PV3D. That transformationdata could get lost when copying geometrydata.

Solution: I “ugly”-solved it this time, just rotating every single mesh of mine -90 in x-axis so you wont notice a difference in the end.

I’ve decided to create a new page in here with just the latest compiled version of the game. Make sure to come in here from time to time to check the progress of the game. Sometimes it might look ugly as I’m testing stuff but most of the time I hope you will see the progress of it.

Now there is only one core object I need to create before I an start putting all these pieces together to something looking like a game. We need special effects (!) explosions, lightbeams, dust on the ground, flares… things that makes all the difference that is :)





Huge update now. Are you ready?

29 01 2009

Problem with writing a blog about such a creative thing as developing a game is that things happens very fast and sometimes very, very much.

It’s a good thing of course. I don’t have to bother about if I do have something to write about but already now understand that it is very dificult to find a balance between documenting it all carefully but pulling the brakes too much and getting all those creative ideas down on paper (yes digital ones) just to look back and see if they (you) ever will be able to understand and follow what just happened.

I still have decided that some parts of this game must be covered in shadow. not because I’m scared that you’ll exploits my darkest secrets but just the fact that they are not really interesting when it comes to the core subject: building a game with AS3 and PV3D. Remember this carefully now: IF you find yourself saying: “whoaa, how did he do that?” or “hey?? Where did THAT suspicious and geniously functional class come from?” it is just normal. I won’t cover every class and function anymore. Still remember THIS even carefullier: If you are very much interested in finding out exactly HOW I did it it or where you could find that seductive  class of mine, just write me a comment and I’ll try to fit it in.

Why did I tell you this right now? Because I’ve been coding today :) I will from now on try to pack all my source into zip-files so you don’t have to write down every stupid line in here. Still, I believe that reading and writing yourself (and destroying the code with reckless experiments) is the best way to learn.

THIS IS WHERE WE ARE NOW

Let’s see what we got:

First of all. A lot of previous classes has been updated and changed due to.. well new thinking I guess.

The things a just want to sweep away at the moment is the MeshManager and AssetsLoader classes I created. AssetsLoader is called at the init start of the whole game and handles all loading of all assets (duh!).  MeshManager is the Managerclass I have to retrieve the meshes when I need them just by sending in an id so you will see me call this class from time to time so you only need to know that I send in an ID and get a DisplayObject3D.  Yes, it’s kind of a magic box ;)

Let’s then skip Main.as (where all assets are loaded). You can look at it in the zipfiles.

With loading out of the way the View3D is a lot cleaner now. Let’s take a look at that instead:

package
{
    import flash.events.Event;   
    import managers.MeshConstants;
    import org.papervision3d.lights.PointLight3D;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.view.BasicView;
    import org.papervision3d.view.layer.util.ViewportLayerSortMode;
    import se.xcom.framework.managers.MeshManager;
    import units.*

    public class View3D extends BasicView
    {
        private var defender:AUnit
        private var light:PointLight3D
        private var topDepth:uint = 100

        public function View3D()
        {
            super();

            initScene()
            createGround()
            createDefender()

            this.startRendering()    // never ever forget to start this one
        }

        private function initScene():void
        {    // inits all basic stuff like camera, light and.. stuff

            // sets ViewportLayers to sort using index-numbers. (just like the DisplayList)
            viewport.containerSprite.sortMode = ViewportLayerSortMode.INDEX_SORT;

            this.camera.y = 3060
            this.camera.z = -4001
            this.camera.zoom = 230 // now look here! you can zoom!

            light = new PointLight3D()
            light.x = 1000
            light.y = 5000
            light.z = -6000
            scene.addChild(light)
        }

        private function createGround():void
        {
            var tGround:DisplayObject3D = MeshManager.getInstance().getMesh(MeshConstants.GROUND)
            tGround.scale=25
            scene.addChild(tGround)
            // Putting the ground in it's own ViewportLayer. Also setting an index-number to it.
            viewport.getChildLayer(tGround, true).layerIndex = ++topDepth;

        }
        private function createDefender():void
        {
            defender = new Defender(0)    // creates our Defender. '0' is the ID and could be any number at this stage of development.
            scene.addChild(defender.mesh)    // News: I removed the DisplayObject3D extension on AUnit so the mesh needs to be added
            viewport.getChildLayer(defender.mesh, true).layerIndex = ++topDepth;    //The unit is rendered on its own viewPortLayer.
        }

        override protected function onRenderTick(event:Event = null):void
        {
            defender.transformUnit();
            super.onRenderTick(event);
        }
    }
}
The greatest news in here is that Defender only takes an ID and nothing more. Everything else (the composition of components) is handled within the specific Defender-class (as Defender is a unique unit and will look and behave in just one way). We’ll look into that one soon.
The other news is Viewport-thingie. As I mentioned earlier, the viewport is like the TV-screen that shows exactly what the camera is looking at (filming). But the viewport does have layers, just like every flash user are used to with simple 2D. As a default every object in the 3D world is put into the same layer and therefor are rendered at the same time. But just like the 2D layers, you can move some objects to another layer and that layer will be rendered AFTER the layer underneath is finished rendering. The end result is that all objects on the layer “above” will be fully visible and not being overwritten by an object from the previous layer. Just learn what it is. I will come back to the question WHY we would want to do such a thing.
Oh and I placed a ground there too. This is not really news, you know how to do that already. But in the end that is what will be visible as progress (not te thousands lines of code behind the rest of the update :D)
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:         think of this as left and right (-1 1)
        *    vertical:             think of this as up and down (1,-1)
        *    newLastPosition:    if true then these values are used: , posX:, posY:, rotation:
        *    mouseDistX:            how far the mouse has been moved horizontally since last update
        *    mouseDistY:            how far the mouse has been moved vertically since last update
        */

        function getControl():Object    // gets the control object
        function updateControl():void    // updates the calues and creates an object
    }
}
Oh look! I updated the IUnitControler interface. Some people will now be saying “AAAHH BUPUPUPUPP. You are not supposed to change an interface like that. The gang of four told us that…” – Screw you I say! (not the Gang Of Four, I like guys with open-source-beards) The game is still in design state so I redesign my interface as much as I want to. “Why can’t you change interfaces” might some other guys now say. -Shut up! You are wasting blogspace! Let’s talk about my new interface.
Most important with the update is that there is now 2 functions that must be in a controller. Added is an UPDATE function that actually recieves all control data and creates the controlobject that will be sent. This has unloaden the burden for the getControl() function that just passes that object out. Main reason why I did this is that it seems like one unit might need to get the latest update several times within one frame so just getting the same object will not only save time but also the new object parameter: mouseDistX and mouseDistY will not screw up. They just show how far the mouse has been moved since last update.
package controllers
{
    import flash.ui.Keyboard;

    import interfaces.IUnitController;

    import se.xcom.input.ArcadeKeyboard;

    public class LocalController implements interfaces.IUnitController
    {
        private var controlObject:Object
        private var key:ArcadeKeyboard
        private var lastMouseX:Number
        private var lastMouseY:Number

        public function LocalController()
        {
            key = new ArcadeKeyboard(Main.scope)
            lastMouseX = Main.scope.mouseX
            lastMouseY = Main.scope.mouseY
        }

        public function getControl():Object
        {
            return controlObject;
        }

        public function updateControl():void
        {
            // getting up, down, left, right from keyboard
            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++
            }

            // calculating movement of mouseX and mouseY
            var mouseXdist:Number = lastMouseX-Main.scope.mouseX
            var mouseYdist:Number = lastMouseY-Main.scope.mouseY
            lastMouseX = Main.scope.mouseX
            lastMouseY = Main.scope.mouseY

            // creates new controlObject
            controlObject = {vertical:tVert , horizontal:tHoriz , mouseDistX:mouseXdist , mouseDistY:mouseYdist , newLastPosition:false}
        }

    }
}
The new LocalController now looks like this. Any questions about that? no? good (what, you wonder about that Main.scope call??? check Main.as in the zip-file and leave me be)  Moving further… to.. the fancy…
package units
{
    import controllers.*;

    import interfaces.*;

    import managers.MeshConstants;

    import org.papervision3d.materials.ColorMaterial;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.objects.primitives.Sphere;

    import se.xcom.framework.managers.MeshManager;

    import transformers.*;

    import weapons.*;

    public class Defender extends AUnit
    {
        private const CANNON_ANGLE_MAX:int = 75
        private const CANNON_ANGLE_MIN:int = 10

        private var mCannon:DisplayObject3D
        private var mBody:DisplayObject3D

        public function Defender(id:uint)
        {
            var tMesh:DisplayObject3D = initMesh()
            super(tMesh,new LocalController(),new CarTransform(9,0.85,0.2),new MissileLauncher(),id);
        }

        private function initMesh():DisplayObject3D
        {
            // in this function I fetch my meshes with my newly built Meshmanager
            // unfortunately the meshes are not centered nor scaled correctly
            // so I need to tweak them a lot before they are correctly placed.
            // There are 2 meshes. One body and one cannon. They are all a part of
            // “wholeMesh” that is sent to AUnit construcor.
            var wholeMesh:DisplayObject3D = new DisplayObject3D()
            var tMan:MeshManager = MeshManager.getInstance()
            mBody = tMan.getMesh(MeshConstants.DEFENDER)
            mBody.rotationY = 180
            mBody.z += 165
            mBody.x += 180
            mBody.scale = 50
            wholeMesh.addChild(mBody)

            // to be able to rotate my cannon at desired axis, I create a DisplayObject
            // and puts the cannon inside it. Rotation pivot point is always 0,0,0 so I just
            // move my cannon inside so itgets the desired pivot point.
            mCannon = new DisplayObject3D()
            var tMesh:DisplayObject3D = tMan.getMesh(MeshConstants.DEFENDER_TOWER)
            tMesh.rotationY = 180
            tMesh.z -= 30
            tMesh.x -= 70
            tMesh.y += 35
            tMesh.scale = 50
            tMesh.scaleZ = 60
            mCannon.addChild(tMesh)
            mCannon.y = 85
            mCannon.x = -185
            mCannon.rotationZ= 8
            wholeMesh.addChild(mCannon)

            return wholeMesh;
        }

        //
        override public function transformUnit():void
        {
            // Here I call the same function at the parent class AUnit.
            super.transformUnit()

            // get already updated control object.
            var tObj:Object = control.getControl()

            // set cannon rotation by mouseY movements
            mCannon.rotationZ += (tObj.mouseDistY/10)

            // set cannon angles within boundaries
            if (mCannon.rotationZ >this.CANNON_ANGLE_MAX)
            {
                mCannon.rotationZ = this.CANNON_ANGLE_MAX
            } else if (mCannon.rotationZ < this.CANNON_ANGLE_MIN)             {                 mCannon.rotationZ = this.CANNON_ANGLE_MIN             }          }     } }[/sourcecode] So here it is! The updated and enhanced Defender-class. Now a lot more code has been added, not only new features but a lot of the "building up a unit" will be inside the final unit-classes like this. Let's go through it and see if we can learn something new. First of all you can see that I override the transformUnit function that is defined in AUnit. I actually tells Flash to go with this new function instead of AUnit’s old one. Now, there are important code in AUnit’s function that I need to be run so I just start with calling super.transformUnit meaning that I call and run the function transformUnit() in the parent class (super class).  The rest of the function rotates the cannon angle due to mouse movements (try the compiled swf above!).

The other thing that I’d like to mention is the way I set the pivot angle of the cannon. If you are familiar to rotating with AS3 since before this is no news to you but everything is rotated using 0,0,0 (origo) as the pivotpoint. So now when I doesn’t want that as my pivot I need to put the cannon inside another DisplayObject3D and then move it around so that the point of rotation winds up on exactly the local 0,0,0 in that new DisplayObject3D. Then finally I rotate my whole DO3D and voila, my cannon is rotating just like it should.  A few other small tweaks here and there are made in the classes but I guess you can look at them yourselves. I just post this post now (of 1803 words.. blog record?) and Post a new one when the compiled SWF and the source is ready for download.

(1844 now)





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?





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





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!