Thursday, October 25, 2007

Catching up on Cardboard Land

It might be useful to explain this project for anyone trying to figure out what my various mind dumps are all about.

Cardboard Land is a simple game where you are a cardboard man living in a world of cardboard. It is up to you to venture out from the safety of your village to find supplies. You must find as many as possible across the lands. These supplies are objects such as; glue, staplers, tape, paper clips, etc.. On your adventure you will encounter disastrous adversaries, such as; scissor people, water, tornados, huge piles of chewed gum, and possibly fire people.

Simple enough, I suppose. Here are some of my favorite screenshots so far.











Stay tuned for more real information as it occurs.

Tuesday, October 23, 2007

Tornados in Cardboard Land

I started working on a wind area trigger within torquescript, and ended up creating a tornado because that is a fairly interesting effect to recreate. As this is a fairly short script, I'll just paste it here with all my comments and possibly add some stuff.
The flow is this: I create a trigger of my defined type, which should call the onAdd callback to initialise my tornado shape and particle emitter. However, somehow the onAdd isn't being called, so I'm just doing it explicitly. There are two main features of this script, a loop that runs every 50 ms when a player is intersecting my trigger, which takes the difference in positions between the player and trigger, then uses that information to build up some impulse vectors to pull the player in, and spin him around the z axis of my trigger. The second loop is independent of intersection, and is used to move the object around in a random manner. I created a momentum vector for the XY plane to keep the thing from just jumping around, and devised an "adjustment" vector to pull it towards the initial position if we stray too far from there.

Here are the two important functions:

function WindTrigger::onTickTrigger(%this,%trigger) {
%max = %trigger.getNumObjects();
for (%n=0;%n<%max;%n++) {
%obj = %trigger.getObject(%n);
if (%obj.getClassName() $= "Player") {
//find XY distance to player
%pos = VectorSub(%obj.getPosition(),%trigger.getWorldBoxCenter());
%posX = getWord(%pos,0);
%posY = getWord(%pos,1);
%dist = VectorLen(VectorNormalize(setWord(%pos, 2, "0.0")));
//calculate circular tangent vector and apply centripetal force to maintain circular movement
%windX = -%posY - 5*%posX;//mSin(%posX)*mCos(%posY);
%windY = %posX - 5*%posY;//mSin(%posY)*mCos(%posZ);
%windZ = 10;//mSin(%posZ)*mCos(%posX);
%obj.applyImpulse(%obj.getPosition(),VectorScale(%windX SPC %windY SPC %windZ,100*(1.5-%dist)));
}
}
Parent::onTickTrigger(%this,%trigger);
}

function WindTrigger::moveMe(%this,%trigger) {
//get our scale
%scale = %trigger.getScale();
%scaleX = getWord(%scale,0);
%scaleY = getWord(%scale,1);

//compute an adjustment vector to apply on top of
//our movement to keep within some distance of original position
%pos = %trigger.getPosition();
%adjustment = VectorSub(%trigger.startPos,%pos);
%adjDist = VectorLen(%adjustment);
%adjustment = VectorNormalize(%adjustment);
%adjX = 0;
%adjY = 0;
//stay within 25 units of original position (or try to)
if (%adjDist > 25) {
%adjX = getWord(%adjustment,0);
%adjY = getWord(%adjustment,1);
}

//random(-.25,.25) with a step of .01
%trigger.mvX += getRandom(-25,25)/100.0 + %adjX;
%trigger.mvY += getRandom(-25,25)/100.0 + %adjY;
//cap movement to [-1,1]
if (%trigger.mvX <= -1)
%trigger.mvX = -1;
if (%trigger.mvX >= 1)
%trigger.mvX = 1;

if (%trigger.mvY <= -1)
%trigger.mvY = -1;
if (%trigger.mvY >= 1)
%trigger.mvY = 1;

//find our new position
%posX = getWord(%pos,0)+%trigger.mvX;
%posY = getWord(%pos,1)+%trigger.mvY;
%posZ = getTerrainHeight(%posX+5 SPC %posY-5);

//move trigger
%trigger.position = (%posX) SPC (%posY) SPC %posZ;
%trigger.setScale(%trigger.getScale());

//adjust to center for inner objects
%posX += %scaleX/2;
%posY -= %scaleY/2;
%pos = %posX SPC %posY SPC %posZ;

//update StaticShape and ParticleEmitter positions
%trigger.myTornado.position = %pos;
%trigger.myTornado.setScale(%trigger.myTornado.getScale());
%trigger.myParticles.position = %pos;
%trigger.myParticles.setScale(%trigger.myParticles.getScale());

//make sure we get called again
%this.schedule(100,"moveMe",%trigger);
}

It works pretty well, but I haven't added anything to turn off all this simulation when the player is not near the tornado area. I think I may just put a large trigger around the area to enable/disable the tornado set when the player enters and leaves the area. I'll have to play around with this to see if it is sufficiently useable, otherwise I might need to turn down the delays so it doesn't use up as much resources.

Primer

Well, I guess I should start documenting my development in ways other than filling up my desk with post-it notes. So, this place is as good as any. I believe I will start with my Cardboard Land game, and just go from there instead of trying to catch up (and remember various thoughts that have slipped through the cracks). So stay tuned, listeners (haha, radio) for information will establish itself right here.