Skip to content

Instantly share code, notes, and snippets.

@antonkudin
Last active April 26, 2021 10:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save antonkudin/b05f6df189424c1af2406a6d645dfbb3 to your computer and use it in GitHub Desktop.
Save antonkudin/b05f6df189424c1af2406a6d645dfbb3 to your computer and use it in GitHub Desktop.
class treeThing {
// tree design: all the changable variables in one place!
struct treeStyle {
// skipping stuff like how many branches per tree, sticks per branch..
// sticks
Vector2 stickAngleJagMM; // how jaggy the branches are (min-max)
Vector2 stickLengthMM; // how long the sticks are (min-max)
sprite[] sprites; // sprites to be assigned to sticks, can be assigned based on seed or using
// stick's branch position to get the 'leaf' shape if you have arrange this array
// [0-5] small leaf > [6-10] big leaf > [11-20] small leaf, or similar
// spring parameters to be assigned to sticks, from root of branch to its tip
float springFreqRoot;
float springFreqTip;
float springDampRoot;
float springDampTip;
// branches
Vector2 branchAngleMM; // branch angles (min-max)
int maxSubBranches; // how many sub-branches can branch have?
float subBrachChance; // chance a stick will have a sub branch growing on it (0-1)
}
class tree {
float tSeed; // seed (0-1)
branch[] branches;
}
class branch {
float bSeed; // seed (0-1)
float bAngle; // if you want branch to be at an angle
stick[] sticks;
void init(ref int subLeft, treeStyle style){ // subLeft is how many sub-branches this branch can have.
foreach(var stick in sticks){
stick.sAngle = style.stickAngleJagMM.lerp(stick.seed); // Vector2.lerp here is just lerp(v.x, v.y, t);
stick.length = style.stickLengthMM.lerp(stick.seed);
stick.posOnBranch = sticks.indexOf(stick)/(sticks.length-1);
stick.freq = style.springFreqRoot.lerp(stick.posOnBranch);
stick.damp = style.springDampRoot.lerp(stick.posOnBranch);
stick.mySR.sprite = style.sprites[ style.sprites.length * stick.seed ]; // dont forget to limit this index.
// potentially can set other properties of the sprite, like color:
// stick.mySR.color = gradient.evaluate(stick.posOnBranch); - to get nice gradient along the branch
if(subLeft>0){
subLeft--;
stick.subBranch = new branch();
stick.subBranch.init(ref subLeft); // init the branch here, but remember
// to pass subLeft so not to run into infinite sub-branches
}
}
}
void updateBranch(Vector2 walkPosition, float walkAngle, float gravity, float deltaTime){
// starting calculating branch
float mass = 0;
foreach(var stick in sticks)
stick.update(ref walkPosition, ref walkAngle, ref mass, gravity, deltaTime);
}
}
class stick {
float sSeed; // seed (0-1)
float posOnBranch; // where on branch it lays (root=0, tip=1)
Vector2 sPosition; // world position of this stick
Vector2 velocity; // stick velocity last frame
float sAngle; // default angle
float length; // length, obv
float freq, damp; // spring variables
renderer mySR; // however youre rendering your stick
branch subBranch; // if you want sub-branches, you'd have it here
void update(ref Vector2 walkPosition, ref float walkAngle, ref float mass, float gravity, float deltaTime){
mass += length;
walkAngle += sAngle;
Vector2 stickDir = new Vector2(0,length).rotate(sAngle);
Vector2 stickEndPos = walkPosition + stickDir + new Vector2(0, mass*gravity); // where does this stick end?
// using Vector2 spring here, like this: http://allenchou.net/2015/04/game-math-numeric-springing-examples/
sPosition = spring(
sPosition, // current position
stickEndPos, // target position
ref velocity, // get and record back velocity of this stick spring
damp, // damping
freq, // freq
deltaTime
);
// this bit is important to keep sticks never change 'length'
Vector2 newDir = sPosition - rootPos;
sPosition = rootPos + newDir.normalized * length; // .normalized makes vector be length of 1
walkPosition = sPosition;
// update stick's renderer
mySR.position = walkPosition;
mySR.rotation = walkAngle; // or you can just newDir.angle() or similar
if(subBranch!=null){ // stick has sub-branch, lets update it recursively
Vector2 subWalkPosition = walkPosition; // new starting position for this branch
float subWalkAngle = sAngle + walkAngle + subBranch.bAngle; // and angle
subBranch.updateBranch(subWalkPosition, subWalkAngle, gravity, deltaTime);
}
}
}
void init(
treeStyle style, // contains your tree design
float seed // main seed from which every other should be derived from (0-1)
){
// skipping init of tree, branches, seeds, arrays, renderer here..
foreach(var branch in tree.branches){
int subLeft = style.maxSubBranches; // how many sub-branches this branch can have?
// potentially. could be randomized.
branch.bAngle = branchAngleMM.lerp(branch.bSeed);
branch.init(ref subLeft, style);
}
}
void update(
Vector2 rootPos, // current world position
float rootAngle, // current tree angle
float gravity, // will be used to pull down the branches
float deltaTime // frame duration
){
foreach(var branch in tree.branches){
float walkAngle = rootAngle + bAngle;
Vector2 walkPosition = rootPos; // this can be offset using branch's seed,
// if you want several branches in an area instead of one root position
branch.updateBranch(walkPosition, walkAngle, gravity, deltaTime);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment