Refactor / ReWrite
by Jeremy Easoz · in Torque Game Builder · 10/13/2008 (2:52 pm) · 12 replies
I need a little help rewriting a function. (Yeah it's not pretty)
I've been working on a puzzle game off and on for awhile now.
The function above is a refill function that is called after a tile layer is collapsed.
www.jeremyeasoz.com/partial_fill.jpg
The function works but as you see from the image, it looks like the stones are sliding out from behind each other, that effect is not what i'm looking for.
I tried a stack approach, each time through the loop %dropSpacing += %dropSpacing (48)
so that the blocks were stacking on top of each other outside the screen and would fall
down in a line. This takes a long time for the stones to fall down though being stack that high out of the screen.
What I want is something similar to most puzzle games.
Bejeweled as an example.
When they clear the jewels they drop down with spacing in between them and pick up speed as they fall.
Seems pretty hard to do using moveTo.
I would have to call moveTo per tile and change the speed an position.
Anyone else have any better ideas?
function partialFillAreaColumn(%area, %x, %dropIncrementer)
{
// Is the column already full?
%columnCheck = countAreaColumnStones(%area, %x);
if(%columnCheck == 15)
{
return;
}
// Number of stones to be filled
%stoneCount = ($stoneAreaCountY) - %columnCheck;
if(%stoneCount == 0)
{
return;
}
// Drop Position
%topTileWorldPos = getAreaTileWorldPosition(%area, %x, 0);
// Drop Modifier (how far to drop from the Drop Position)
%dropModifier = (%stoneCount - 1) * %dropIncrementer;
%dropSpacing = 48;
while(%stoneCount > 0)
{
// Get an object from the object pool
%obj = $stoneObjectPool.get_object();
// Check the number of spelltaps in the area
// and make sure theres atleast one.
if($spellTapCheck == 0)
{
%obj.setAnimation($randomSpellTapArray[createRandomSpellTap(0, 6)]);
$spellTapCheck++;
}
else
{
%obj.setAnimation($randomStoneArray[createRandomStone(0, 68)]);
}
// Set the objects position 48 above the tile layer (outside the screen)
%obj.setPosition(getWord(%topTileWorldPos, 0), getWord(%topTileWorldPos, 1) - %dropSpacing);
if(%area $= "playerStoneArea")
{
%obj.setSize("48 48");
%obj.setGraphGroup(1);
}
if(%area $= "enemyStoneArea")
{
%obj.setSize("24 24");
%obj.setGraphGroup(2);
}
%obj.moveTo(getWord(%topTileWorldPos, 0), getWord(%topTileWorldPos, 1) + %dropModifier, 1000, true, true, true);
$stoneObjectPool.remove(%obj);
%dropModifier -= %dropIncrementer;
%stoneCount--;
}
}I've been working on a puzzle game off and on for awhile now.
The function above is a refill function that is called after a tile layer is collapsed.
www.jeremyeasoz.com/partial_fill.jpg
The function works but as you see from the image, it looks like the stones are sliding out from behind each other, that effect is not what i'm looking for.
I tried a stack approach, each time through the loop %dropSpacing += %dropSpacing (48)
so that the blocks were stacking on top of each other outside the screen and would fall
down in a line. This takes a long time for the stones to fall down though being stack that high out of the screen.
What I want is something similar to most puzzle games.
Bejeweled as an example.
When they clear the jewels they drop down with spacing in between them and pick up speed as they fall.
Seems pretty hard to do using moveTo.
I would have to call moveTo per tile and change the speed an position.
Anyone else have any better ideas?
About the author
#2
I like this method better because I get guaranteed behavior.
10/14/2008 (3:05 pm)
I've accomplished this in the past by manually setting the positions of my objects. The t2dSceneGraph has an onUpdateScene() which gets called every tick. I then get the time since the last call to it and update the velocity and positions manually.I like this method better because I get guaranteed behavior.
#3
When moveTo reaches it's position the current object is removed from the scenegraph and
a copy is inserted into the tilelayer.
If I use gravity/collisions, I have to wait for all the objects to stop moving, remove them from the scenegraph while copying them into the tilelayer.
10/14/2008 (4:26 pm)
Well, I guess I left out a small part of my code.When moveTo reaches it's position the current object is removed from the scenegraph and
a copy is inserted into the tilelayer.
function t2dSceneObject::onPositionTarget(%this)
{
// Check the graph group
if(%this.getGraphGroup() == 1) // playerStoneArea
{
%tile = playerStoneArea.pickTile(%this.getPosition());
playerStoneArea.setAnimatedTile(getWord(%tile, 0), getWord(%tile, 1), %this.getAnimation());
%this.safeDelete();
$stoneObjectPool.recycle_object();
}
if(%this.getGraphGroup() == 2) // enemyStoneArea
{
%tile = enemyStoneArea.pickTile(%this.getPosition());
enemyStoneArea.setAnimatedTile(getWord(%tile, 0), getWord(%tile, 1), %this.getAnimation());
%this.safeDelete();
$stoneObjectPool.recycle_object();
}
}If I use gravity/collisions, I have to wait for all the objects to stop moving, remove them from the scenegraph while copying them into the tilelayer.
#4
10/14/2008 (4:31 pm)
Can I call moveTo with a speed of 0, yet apply gravity to do the movement?
#5
I'm confused though.
I created a stack of blocks outside the screen.
They don't seem to all fall at the same speed though.
I would assume they would all fall in a large column if they all had the same speed,
but the top blocks take forever to fall.
10/14/2008 (5:02 pm)
I tried, moveTo with a speed of 0 and setConstantForcePolar to move the object in a downward motion.I'm confused though.
I created a stack of blocks outside the screen.
They don't seem to all fall at the same speed though.
I would assume they would all fall in a large column if they all had the same speed,
but the top blocks take forever to fall.
#6
Now, the property of each jewel should include:
* A collision rectangle that covers an entire grid square, not just the jewel.
* A Constant Y force applied with gravity ticked if you want it to start slow and build up.
For each jewel I would also enter their object id 's into a lookup table so you can ensure all of the jewels have finished moving before the user can click. As well as this, I would store a position variable for each jewel within the game board area from the bottom up, left to right. So far instance, the bottom left jewel would be 1,1. The next jewel along would be 1,2, etc.
The next step would be to create a function that is called when the player successfully performs an action. Each time this function is called it would do the following items:
* Find the affected jewels
* Play your destruction animation on each jewel
* safe delete the item
* Change the jewels above the affected jewels to reflect the movement down the grid
* Set a flag to tell the system that jewels are being moved.
* Disable mouse clicks
Then, in your on update function, do a test to see if the jewels being moved flagged is enabled and do the following if they are:
* Check to ensure all jewels are in their correct spot
* Check to ensure all jewels have a velocity of 0
* Check the "off board" section to ensure there are additional jewels spawned
* Re-enable mouse clicks when done.
This make sense ?
10/14/2008 (9:20 pm)
Ok, I think I understand what you are trying to here and this is how I would approach it. Let's use a bejeweled style match-3 scenario as our example. Say your playing board is 8 squares across and 8 squares down filled with "jewels" (In my great ASCII drawings below, the "X" represent a jewel). Now we need to get the maximum amount of space the jewels can drop down when the user correctly performs an action. In the case of mast match 3 games, this is 5 (A match five line). Because we are dropping jewels down from the top, this means we need to load an additional 5 rows of jewels above our game board. You can hide this area behind a GUI or "off camera". We should now have something like the following:| X X X X X X | | | | X X X X X X | | | | X X X X X X | | | | X X X X X X | | | | X X X X X X | |~~~~~~~~~~~~~~~~~| | X X X X X X | | | | X X X X X X | | | | X X X X X X | | | | X X X X X X | | | | X X X X X X | | | | X X X X X X | | | | X X X X X X | | | | X X X X X X | ~~~~~~~~~~~~~~~~~
Now, the property of each jewel should include:
* A collision rectangle that covers an entire grid square, not just the jewel.
* A Constant Y force applied with gravity ticked if you want it to start slow and build up.
For each jewel I would also enter their object id 's into a lookup table so you can ensure all of the jewels have finished moving before the user can click. As well as this, I would store a position variable for each jewel within the game board area from the bottom up, left to right. So far instance, the bottom left jewel would be 1,1. The next jewel along would be 1,2, etc.
The next step would be to create a function that is called when the player successfully performs an action. Each time this function is called it would do the following items:
* Find the affected jewels
* Play your destruction animation on each jewel
* safe delete the item
* Change the jewels above the affected jewels to reflect the movement down the grid
* Set a flag to tell the system that jewels are being moved.
* Disable mouse clicks
Then, in your on update function, do a test to see if the jewels being moved flagged is enabled and do the following if they are:
* Check to ensure all jewels are in their correct spot
* Check to ensure all jewels have a velocity of 0
* Check the "off board" section to ensure there are additional jewels spawned
* Re-enable mouse clicks when done.
This make sense ?
#7
10/15/2008 (12:14 am)
If they are falling and its basically working right now, you just want them to accelerate, you might be able to use a constant force, or just manually give them more +y velocity on a regular basis as they fall. You can start them moving with a moveTo if you want, the onPositionTarget will still be called whenever they reach (within the tolerance) of the target, even if you modify their velocity later on.
#8
They just need to pick up speed.
I think I can get what I want with t2dSceneGraph::onUpdateScene
I'll just need to write a function that pulls all the t2dAnimatedSprites out of the SceneGraph so I can apply a speed change to them.
getSceneObjectList() ??
10/15/2008 (7:16 am)
Yeah, they already move pretty close to what I want now.They just need to pick up speed.
I think I can get what I want with t2dSceneGraph::onUpdateScene
I'll just need to write a function that pulls all the t2dAnimatedSprites out of the SceneGraph so I can apply a speed change to them.
getSceneObjectList() ??
#9
10/15/2008 (11:34 am)
Yeah you could do that, or put them in a simset to loop through ( you might already have one ), or use the timer functionality all t2dSceneObject's have, lots of possibilities.
#10
10/21/2008 (2:12 am)
Incase anyone is reads this one possible way to loop through objects in a scene%list = scenegraph.getSceneObjectList();
for(%i = 0; %i < getWordCount(%list) - 1; %i++)
{
%obj = getWord(%list, %i);
if(%obj.getClassName() $= "t2dAnimatedSprite")
//DoSomething
}
#11
for ( %i = 0; %i < getWordCount(%list); %i++ )
{
...
}
eg, "1025 1026 1027", word count = 3, loop from 0, 1, to 2
10/21/2008 (9:27 am)
I think that's actually skipping the last object, you want,for ( %i = 0; %i < getWordCount(%list); %i++ )
{
...
}
eg, "1025 1026 1027", word count = 3, loop from 0, 1, to 2
#12
the main disadvantage of going in reverse is that it's non-standard,
and so makes the code slightly more effort to maintain.
10/21/2008 (10:33 am)
Lately i've been a fan of looping in reverse, ala:for (%n = getWordCount(%list) - 1; %n >= 0; %n--)
{ }because it both avoids evaluating getWordCount(%list) each time through the loop and creating a temporary "count" variable, as in:%num = getWordCount(%list);
for (%n = 0; %n < %num; %n++)
{ }the main disadvantage of going in reverse is that it's non-standard,
and so makes the code slightly more effort to maintain.
Torque Owner Glenn Prince
EDIT- I should really explain further.
I would turn on CLAMP collisions on all the blocks and have the bottom "platform" a collidable object. Apply a gravity to the scene and when you destroy the blocks they will "fall" and increasing speed and stop when they hit the bottom.