3D-Collisions basics

13 02 2009

One thing that is absolutely vital in most games is the actual event when two objects somehow collides.

Be it bullets that collides with it’s target, wheels touching the floor, a paperMario reaching the end of the map or just a FPS-player that tries to walk through a wall, we just need to see whether something is touching something else (especially if inappropriate :) ) Now, there are several ways to detect this and as usual it’s all about processor vs quality. The absolute best and accurate way to do this is to let every single face check with every other single face out there if it has intersected and then dispatch that a collision has occured. Now, this (we call it face <-> face collision) is extremely demanding and even top notch 3D accelerated AAA-titles barely uses it so let’s just put that aside for the mathgeeks and dreamers and let’s look at some realistic aternatives.

Let us start in the other end. How fast can we go??? Well, I say (you can bash me as much as you want to, I have not studied this at all) that he fastest kind of collisiontest you can have is to just make a static numbercheck.

if (mesh.y < 0) { mesh.y = 0}

Yes, we all fid it extremely obvious but sometimes people make things WAY to difficult for them. Still in this game I have used this collisiontype many times where some people would have tried a more demanding approach just for the sake of being dynamic. Just because of the processorpower it takes to detect collisions I have purposely chosen to create a rectangular arena, opposite to the arena I used in my last game. It doesnt have any walls at the moment but when it get walls I don’t have to create some difficult collisioncheck, just a static numbercheck will make the job!

What about the ground?? Well I could have added bumbs in a sandy arena but now I choose a flat one for several reasons.

1. As soon as something like the grenade goes Z < 0 it will bounce up again.

2. When it’s flat and no units will be able to jump/have physics, I can remove all bottom faces of the unit. You should see them, they are all stripped and seethrough from underneath.

3. Putting obstacles on the arena (extra walls, barrels etc) is as easy as Z=0

Now you probably already knew this stupid collisioncheck but I still want you all to remember this simple solution when creating your design for the game. Maybe your 3D pong should go with square walls instead of your freakishly new plasmastyle.

Now, lets start with some “real” collisiontesting then. After the static one, I might be brave enough to say that the next least perfomancedemanding collisioncheck is a single distancecheck. “How far from this object is that object?? Is it to close? then BOOOM!” -style.

In Papervision we got the math already done with it’s  function: DisplayObject3D.distanceTo(otherObj:DisplayObject3D) .  (no it’s not rocketsciencemath either but it’s nice we don’t have to dig out mr.Pythagoras more than needed)

If the distance is lesser than your set value, then you consider it to be a collision. Now, this method is very rarely used but if we enhance it just a liiiiittle bit you will have one of the most common collisiontests in games…

Sphere-collision

When I was a kid, (yes, I promise i have been) I just couldn’t understand how spherecollision could be faster to use than ermm.. other that we will bring up in a short while. Spheres are complicated and as soon as round shapes are involved it means using PI and Sinus and maybe derivata. No, not this time. If you just think of it for a second: distanceTo() is really a sphere. It doesn’t have any direction but checks the distance in EVERY direction building a kind of a “sphere” around the object where the distance is actually the radius of the sphere. Look at this image:

spherecollision

Here I have set a distanceTo limit on the Defender and a distanceTo limit on the grenade so in code it is just:

if (defender.distanceTo(grenade)- (defender.collisionSphereRadius+grenade.collisionSphereRadius) < 0)  { trace(“defender is FUBAR!!!”)}

It’s all about the distance between the objects but we added some kind of radius to each object simulating it’s size. In my game I have set this radius manually and actually do have a “showCollisionSphere” function on each unit and bullet so I can see that it is somewhat correct with the size of the mesh. Still in Papervision3D DisplayObject3D you already have tis kind of collisiondetection in the function: hitTestObject( obj:DisplayObject3D, multiplier:Number=1 ):Boolean

This function takes the furthest pixels away and creates a radius out of that. This could create a collisionsphere that might not be the best for the whole object and therefor there is also a multiplier parameter if you would like to increase or decrease the size of your “sphere”. It works great (I just wanted to create my own flexible collisioncheck but I recommend using the inbuilt one).

Box Collision

What if my object is very flat? It might even be a plane! Creating a collisionsphere around that would just be stupic as it would, in worst cases, trigger collisions way beyond the actual planes location. The other single method that is used just as much as sphere collisions is the box collision. You have probably done it a thousands times already keeping something within a boundary or similar tasks.. does this looks familiar?

if (obj.x > MAX_WIDTH){obj.x = MAX_WIDTH;}

else if (obj.x < MIN_WIDTH){obj.x = MIN_WIDTH;}

if (obj.y > MAX_HEIGHT){obj.y = MAX_HEIGHT;}

else if (obj.y < MIN_HEIGHT){obj.y = MIN_HEIGHT;}

this is actually the technique to use with box collisions. Just check wether a box is within another box.

In every DisplayObject3D that contains a geometryobject you can somewhat easily achieve this as the geometryobject contains a variable with the freakedout name: aabb

This is actually the bounding box we need ( yes it is short for AxisAlignedBoundingBox). It holds all the MAX and MIN values of your mesh in all 3 dimensions so it’s just a matter of creating a lot of “If”‘ rows and you will have your own box collisiontest. Box collision is not as fast as spherecollision but is a very good alternativ for meshes with different proportions.

This was just some simple theory. I will try to stitch this up in some real code in the game to show you later on. Now already I can tell you that if you want to optimize collisioncheck you really should think about WHICH objects really do need to be checked with each other?? Can I remove some of the collisionchecks without harm? All geometry will probably not need to be checked against each other and even some units doesnt have to be checked with some bullets (eg the unit that shot the grenade doesn’t need to be collisionchecked with the nade). I am fond of lists in different ways so I will probably create one now again where objects subscribes to the list where it needs to check with other objects in that particular list.

59

The just-released StreetFighter IV went back from polygon collision to use classical box-collision just to speed up and recreate the classical feel of the game.

Also one small notice is that there are several other types of collisionchecks but thse are by far the most common ones. They are also very easy to mix together and it’s not unusual that game uses BOX <-> SPHERE collisions and POLYGON <->BOX etc.   Hope I could at least enlighten someone with this basic theoretical text. Have a great time creating things I can play!

Advertisements




Multiplayer in Flash – How to..

5 02 2009

The biggest reason I chose to start up this project at this current date is that before current date it has not been possible to create what I am trying to do , using Flash. In fact, it is not completely possible yet when it comes to some 3D features but I’m an optimist and would like to stay prepared for what both PV3D and Flash has to offer the years to come (yes, I count this project to be in progress for years). Still when it comes to fast paced multiplayer games where two users, sitting by each computer, plays against each other it has just become reality!

Adobe has just opened the (beta)doors to their new protocol (RTMFP) and very shortly it means that.. it can now be done.

If you’re interested right now to try it out wothout reading my oracle guidelines, just head over to Adobes dev. Centre and check out Stratus

Without getting too technical on the subject I want to introduce what the difference is at why we need it, because this article will be about how to think to even be able to create a mp-game using streaming datatransfers client-client.

Netcommunication for dummies

Yes, we have been able to connect 2 (or more) flashclients directly to each other and communicate but until now it has only been available using a TCP-IP like protocol. (if you don’t know what it is, never mind, it is just porn for netfreaks). TCP-IP is very good in the aspect that the same data being sent is actually winding up in the right order and shape that it was sent. So, it is secure and stable. Problem is that the if “recieving client” doesn’t properly get the data sent it will wait until it really really gets it. No other data can be transfered meanwhile and in worst case it can choke up the whole system. In the end TCP/IP assures that the exact data being sent is coming in in the correct order. Maybe great for turnbased games and similar but not for our hot actiongame.

So now, something different has come up.  Adobe’s RTMFP is a UDP-based protocol (porn again) and UDP does not really care if all the data comes in in the exact order. It just keeps on sending and recieving data. This means that no “doublechecks” needs to be done clogging up the system and no chokes happenes if one package gets lost along the way. Don’t you worry, there will always come another package ;)

So basically, finally we got fast and uncontrolled data streaming on Flash (good for cam-streaming and such as well). I will not in this article explain codewise how to set up a connection using this technique but it will surely come as this is very much needed for the game. Now how can we use this? What do we need to consider when building a game?

Movement and actions

Actually, without really telling you, I’ve already tried to think multiplayer when it comes to this aspect already in the game. The first approach every mp programmer tries before knowing better (me included) is to just send the transformationdata to the other gamer and believing that just by sending my position and rotation values should be enough to have a great multiplayer game. The problem you will see is that transfers of data does not sometimes sync with the framerate of the game. Sending a package each and every frame will probably get heavy on the system and there is no saying that all those packages will be recieved at the same rate as they were sent.

Also you must consider the fact that the user on the other side might have a worse computer than you with a much lower framerate. Also there is this horrible lag-issue as it takes time for data to be transferred etc etc.

So we can easily say that we could use some tips here.

Predict the future

If we just could predict the actions of the other gamer we could render his unit due to these predictions. Now we at least try, right? First of all, instead of sending coordinates and rotations only we should also send some controls-data.
Actually the controlsdata is more important than the transformdata. Say you recieve some controldata. You loop through all your units on the screen, first your and transform it due to your controls and then the remote unit using the controldata you just recieved. What happens if you dont get any data next frame??? Well if you based the remote units movement only on coordinates it would get stuck on the same position as before now instead you can assume that if he held the forward button in the last millisecond, the best guess is that he/she probably does that now as well, so you continue calculate a new position using his/her last controldata.

Now whenever you recieve new data, use the new data both to control the unit (using unit data) and “tween” towards the absolutely correct positions and rotations. The result will be something similar to these two pictures:

mp_movement1mp_movement2

As you can see, on the top picture, using only transformdata will keep the unit stuttering to new positions on the frames it recieved new data meanwhile using controldata makes the unit move each frame BUT you will have some misplacement on the unit as it continues cusing the same controldata til a new is recieved. Therefor the controldata needs to be mixed with transformationdata so the most realistic movement can be achieved.

Time is relative

Until now, we have updated the speed and rotation each frame equally. Fine, this might work well in a singleplayer game as you are the only one competing against yourself but what if two players have different capacity on their computers? One computer is an ultramachine updating the game at 35 fps meanwhile the other one is going slow on 5 fps. This means that the fast comp will update the frame 35 times = moving it’s vehicle 7 times more often than the other one. Result is that the guy on the fast computer will have a faster moving unit. Also will he see the other unit move very strange as his computer will calculate the movements on the remote unit faster than it is actually being calculated on the slow computer.

Well you hear where this is leading… people will yell “CHEATERS” at each other and we will not have that cozy, nice and social game that we want. There are a few different solutions to this but the one I really recommend is called Delta Timing.

Move by time, not by frame

Delta Timing is to calculate how much the unit is transforming through time, and not static through each frametick. To achieve this you need to check the timespan between each movement. Let me give you some theory (yes, Ive done that this whole article)…

Assume you want the unit to move 10 pixels each frame. That is if your framerate is 30 FPS constantly. Then we have two good variables to start with, now lets calculate the time it really takes between one movement to the other. My pseudocode would look something like this:


{

//...here goes a lot of gamecode and nice stuff ...

currentTime  = currentTimeInMilliSeconds

timeItTookSinceLastTime = currentTime - lastTime

timeItShouldTake = 1000 / 30  // this gives how many milliSeconds it takes for one frame in 30FPS

timeScaler = timeItTookSinceLastTime / timeItShouldTake // give you a number that should be close to 1 if FPS is good.

lastTime = currentTime

}

With above code (no it’s not working if you try it, it’s just pseudo-mumbo-jumbo) you will get a variable timeScaler that will be lower than 1 if the FPS is actually going higher than 30 and higher than 1 if the FPS is dropping so this exact timeScaler must be used to compensate all speeddrops or speedboosts a FPS could get. So whenever you update, say a movement, each frame. instead of

unit.x += speed

with deltatiming you will now always use

unit.x += speed*timeScaler

Same goes with rotation, weapons, animations, cameramovement and everything that is speeded up or slowed down with your current fps.

Yes I know I haven’t given you a real line of code but the theory needs to be there before we actually create something with it. Now, swap your browser with your favourite AS3 IDE and start playing around with these things. I will soon implent it in the game code.

Cya

/Andreas





ViewportLayers – in depth

4 02 2009

This article has been moved to: http://www.x-com.se/labs

Make sure to visit this new blog for great articles and tutorials regarding PV3D and other flash related subjects.

/Andreas





Links here:

29 01 2009

The compiled swf-file now looks like this (click on the movie to interact with keyboard and mouse)

And the sourcefiles can be downloaded here: (you lazy bastards!)

Thank you for reading and please help me out with comments, critics and questions if someting is unclear (or I’m just a stupid Swede).

/Andreas





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?





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.