Created
June 18, 2019 02:08
-
-
Save reZach/15da63f816e0d20fe8446be30f30f1b5 to your computer and use it in GitHub Desktop.
Animates Terrain in Game Builder (Steam)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Example card. | |
// User-editable properties for this card: | |
export const PROPS = [ | |
propNumber("ticks", 60), | |
propBoolean("infinite", true), | |
propBoolean("completeAnimationDelay", false), | |
propNumber("completeAnimationDelayMin", 60), | |
propNumber("completeAnimationDelayMax", 60), | |
propNumber("forceFrame", -1) | |
]; | |
/** | |
* Sets the block relative to the pos. | |
* @param {THREE.Vector3} pos The relative position (typically an actor) | |
* @param {int} xOffset The x-offset relative to pos where you'd like to place the block | |
* @param {int} yOffset The y-offset relative to pos where you'd like to place the block | |
* @param {int} zOffset The z-offset relative to pos where you'd like to place the block | |
* @param {BlockShape} blockShape The shape of the block | |
* @param {BlockDir} blockDir The direction of the block | |
* @param {BlockStyle} blockStyle The style of the block | |
*/ | |
var sbr = function (pos, xOffset, yOffset, zOffset, | |
blockShape, blockDir, blockStyle) { | |
// Blocks extend 2.5 units on the x-plane, | |
// and 1.5 units in the y-plane | |
var newX = (pos.x + (xOffset * 2.5)) / 2.5; | |
var newY = (pos.y + (yOffset * 1.5)) / 1.5; | |
var newZ = (pos.z + (zOffset * 2.5)) / 2.5; | |
setBlock( | |
newX, | |
newY, | |
newZ, | |
blockShape, | |
blockDir, | |
blockStyle | |
); | |
}; | |
/** | |
* Clears the block relative to the pos. | |
* @param {THREE.Vector3} pos The relative position (typically an actor) | |
* @param {int} xOffset The x-offset relative to pos where you'd like to clear the block | |
* @param {int} yOffset The y-offset relative to pos where you'd like to clear the block | |
* @param {int} zOffset The z-offset relative to pos where you'd like to clear the block | |
*/ | |
var cbr = function (pos, xOffset, yOffset, zOffset) { | |
// Blocks extend 2.5 units on the x-plane, | |
// and 1.5 units in the y-plane | |
var newX = (pos.x + (xOffset * 2.5)) / 2.5; | |
var newY = (pos.y + (yOffset * 1.5)) / 1.5; | |
var newZ = (pos.z + (zOffset * 2.5)) / 2.5; | |
clearBlock( | |
newX, | |
newY, | |
newZ | |
); | |
}; | |
var Animation = (function (origin) { | |
var _tick = 0; // Holds the count of ticks | |
var _frames = []; // All of our frames for our animation | |
var _currentFrame = 0; // The current frame we are showing | |
var _drawnFirstFrame = false; // If we've drawn the first frame yet | |
var _createdCoordinates = false; | |
var _animationCompleteDelayActive = false; | |
var _animationCompleteDelayTimer = 0; | |
var _ended = false; // If the animation should be ended | |
var _origin = origin; // Holds the origin (position (x,y,z)) of this animation | |
var _savedBlocks = {}; // Holds saved blocks used in your animation - to save typing! | |
var createCoordinates = function () { | |
if (_createdCoordinates) { | |
return; | |
} | |
for (var i = 0; i < _frames.length; i++) { | |
for (var j = 0; j < _frames[i].length; j++) { | |
if (typeof _frames[i][j].x === "undefined" || | |
typeof _frames[i][j].y === "undefined" || | |
typeof _frames[i][j].z === "undefined") { | |
_frames[i][j].x = _frames[i][j].xOffset; | |
_frames[i][j].y = _frames[i][j].yOffset; | |
_frames[i][j].z = _frames[i][j].zOffset; | |
} | |
} | |
} | |
_createdCoordinates = true; | |
} | |
/* | |
* Clears out all frames. | |
*/ | |
var clearAllFrames = function () { | |
for (var i = 0; i < _frames.length; i++) { | |
for (var j = 0; j < _frames[i].length; j++) { | |
cbr(_origin, _frames[i][j].x, _frames[i][j].y, _frames[i][j].z); | |
} | |
} | |
}; | |
/** | |
* The main drawing function. | |
* @param {int} frameNum The frame to display | |
*/ | |
var draw = function (frameNum) { | |
createCoordinates(); | |
clearAllFrames(); | |
// Draw new blocks | |
for (var i = 0; i < _frames[frameNum].length; i++) { | |
// Load from saved blocks | |
if (typeof _frames[frameNum][i].block !== "undefined") { | |
var block = _savedBlocks[_frames[frameNum][i].block]; | |
sbr(_origin, _frames[frameNum][i].x, _frames[frameNum][i].y, _frames[frameNum][i].z, | |
block.shape, block.dir, block.style); | |
} else { | |
sbr(_origin, _frames[frameNum][i].x, _frames[frameNum][i].y, _frames[frameNum][i].z, | |
_frames[frameNum][i].shape, _frames[frameNum][i].dir, _frames[frameNum][i].style); | |
} | |
} | |
}; | |
return { | |
/** | |
* Sets the origin (x,y,z) of where this animation should originate from. | |
* @param {THREE.Vector3} origin | |
*/ | |
setOrigin: function (origin) { | |
_origin = origin; | |
}, | |
/** | |
* Saves block data so that you can reference the data by a name, | |
* instead of typing out the block data for each identical block. | |
* @param {Object} block Block information that should be saved | |
* @param {string} name A friendly name of this block | |
*/ | |
saveBlock: function (block, name) { | |
if (typeof _savedBlocks[name] === "undefined") { | |
_savedBlocks[name] = block; | |
} | |
}, | |
/** | |
* To be called from the "onTick" function. | |
*/ | |
play: function () { | |
// If the animation is one-time, | |
// don't attempt to run it again | |
if (_ended && !props.infinite) { | |
return; | |
} | |
// Force a particular frame, only if it's in the | |
// range of available frames. | |
if (props.forceFrame >= 0 && props.forceFrame < _frames.length) { | |
_currentFrame = props.forceFrame; | |
draw(props.forceFrame); | |
return; | |
} | |
_tick++; | |
// Delay the next animation loop based on our props | |
if (_animationCompleteDelayActive){ | |
if (_tick >= _animationCompleteDelayTimer){ | |
_tick = props.ticks; | |
_animationCompleteDelayActive = false; | |
_animationCompleteDelayTimer = 0; | |
} else { | |
return; | |
} | |
} | |
if (_tick >= props.ticks) { | |
_tick = 0; | |
_currentFrame++; | |
if (_currentFrame >= _frames.length) { | |
if (!props.infinite) { | |
_ended = true; | |
clearAllFrames(); | |
return; | |
} else { | |
_currentFrame = 0; | |
// Reset the animation lock timer if enabled | |
if (props.completeAnimationDelay){ | |
_animationCompleteDelayActive = true; | |
_currentFrame = -1; | |
if (props.completeAnimationDelayMin < props.completeAnimationDelayMax){ | |
_animationCompleteDelayTimer = props.completeAnimationDelayMax; | |
} else { | |
_animationCompleteDelayTimer = Math.floor( | |
Math.random() * props.completeAnimationDelayMax + props.completeAnimationDelayMin); | |
} | |
clearAllFrames(); | |
return; | |
} | |
} | |
} | |
draw(_currentFrame); | |
} else { | |
// Draw the first frame (only once) | |
if (!_drawnFirstFrame && _currentFrame === 0) { | |
_drawnFirstFrame = true; | |
draw(_currentFrame); | |
} | |
} | |
}, | |
/** | |
* Adds a block, or an array of blocks to be saved | |
* for a single frame. | |
* @param {array} blocks An array of blocks for a given frame | |
*/ | |
addFrame: function (blocks) { | |
if (!Array.isArray(blocks)) { | |
_frames.push([blocks]); | |
} else { | |
_frames.push(blocks); | |
} | |
}, | |
SHAPES: { | |
PYRAMID: "PYRAMID" | |
}, | |
create: function (shape, options) { | |
var blockData = []; | |
var style = 0; | |
// Load style from block object, | |
// or otherwise saved blocks | |
if (typeof options.block === "object"){ | |
style = options.block.style; | |
} else if (typeof options.block === "string"){ | |
if (typeof _savedBlocks[options.block] !== "undefined"){ | |
style = _savedBlocks[options.block].style; | |
} | |
} | |
/* | |
options: { | |
xOffset: 0, | |
yOffset: 0, | |
zOffset: 0, | |
height: x, | |
dir: "N", | |
block: { | |
shape: BlockShape.BOX, | |
dir: BlockDir.NORTH, | |
style: 26 | |
} | |
} | |
*/ | |
switch (shape) { | |
case this.SHAPES.PYRAMID: | |
if (options.height < 1){ | |
break; | |
} | |
// Create "tip" | |
blockData.push({ | |
xOffset: options.xOffset, | |
yOffset: options.yOffset, | |
zOffset: options.zOffset, | |
shape: BlockShape.CORNER, | |
dir: BlockDir.WEST, | |
style: style | |
}); | |
blockData.push({ | |
xOffset: options.xOffset, | |
yOffset: options.yOffset, | |
zOffset: options.zOffset + 1, | |
shape: BlockShape.CORNER, | |
dir: BlockDir.SOUTH, | |
style: style | |
}); | |
blockData.push({ | |
xOffset: options.xOffset - 1, | |
yOffset: options.yOffset, | |
zOffset: options.zOffset + 1, | |
shape: BlockShape.CORNER, | |
dir: BlockDir.EAST, | |
style: style | |
}); | |
blockData.push({ | |
xOffset: options.xOffset - 1, | |
yOffset: options.yOffset, | |
zOffset: options.zOffset, | |
shape: BlockShape.CORNER, | |
dir: BlockDir.NORTH, | |
style: style | |
}); | |
for (var i = 1; i <= options.height; i++) { | |
// if (i > 1 && i !== options.height){ | |
// // Create "column" support | |
// blockData.push({ | |
// xOffset: options.xOffset, | |
// yOffset: options.yOffset - i, | |
// zOffset: options.zOffset, | |
// shape: BlockShape.BOX, | |
// dir: BlockDir.WEST, | |
// style: options.block.style | |
// }); | |
// blockData.push({ | |
// xOffset: options.xOffset, | |
// yOffset: options.yOffset - i, | |
// zOffset: options.zOffset + 1, | |
// shape: BlockShape.BOX, | |
// dir: BlockDir.SOUTH, | |
// style: options.block.style | |
// }); | |
// blockData.push({ | |
// xOffset: options.xOffset - 1, | |
// yOffset: options.yOffset - i, | |
// zOffset: options.zOffset + 1, | |
// shape: BlockShape.BOX, | |
// dir: BlockDir.EAST, | |
// style: options.block.style | |
// }); | |
// blockData.push({ | |
// xOffset: options.xOffset - 1, | |
// yOffset: options.yOffset - i, | |
// zOffset: options.zOffset, | |
// shape: BlockShape.BOX, | |
// dir: BlockDir.NORTH, | |
// style: options.block.style | |
// }); | |
// } | |
if (i > 1){ | |
// Create pyramid sides | |
for (var j = 0; j < i * 2; j++){ | |
if (j === 0){ | |
blockData.push({ | |
xOffset: options.xOffset + (i - 1), | |
yOffset: options.yOffset - (i - 1), | |
zOffset: options.zOffset - (i - 1) + j, | |
shape: BlockShape.CORNER, | |
dir: BlockDir.WEST, | |
style: style | |
}); | |
continue; | |
} | |
if (j === ((i * 2) - 1)){ | |
blockData.push({ | |
xOffset: options.xOffset + (i - 1), | |
yOffset: options.yOffset - (i - 1), | |
zOffset: options.zOffset - (i - 1) + j, | |
shape: BlockShape.CORNER, | |
dir: BlockDir.SOUTH, | |
style: style | |
}); | |
continue; | |
} | |
blockData.push({ | |
xOffset: options.xOffset + (i - 1), | |
yOffset: options.yOffset - (i - 1), | |
zOffset: options.zOffset - (i - 1) + j, | |
shape: BlockShape.RAMP, | |
dir: BlockDir.WEST, | |
style: style | |
}); | |
} | |
for (var j = 0; j < i * 2; j++){ | |
if (j === 0) { | |
continue; | |
} | |
if (j === ((i * 2) - 1)){ | |
blockData.push({ | |
xOffset: options.xOffset + (i - 1) - j, | |
yOffset: options.yOffset - (i - 1), | |
zOffset: options.zOffset - (i - 1), | |
shape: BlockShape.CORNER, | |
dir: BlockDir.NORTH, | |
style: style | |
}); | |
continue; | |
} | |
blockData.push({ | |
xOffset: options.xOffset + (i - 1) - j, | |
yOffset: options.yOffset - (i - 1), | |
zOffset: options.zOffset - (i - 1), | |
shape: BlockShape.RAMP, | |
dir: BlockDir.NORTH, | |
style: style | |
}); | |
} | |
for (var j = 0; j < i * 2; j++){ | |
if (j === 0){ | |
continue; | |
} | |
if (j === ((i * 2) - 1)){ | |
blockData.push({ | |
xOffset: options.xOffset + (i - 1) - j, | |
yOffset: options.yOffset - (i - 1), | |
zOffset: options.zOffset + i, | |
shape: BlockShape.CORNER, | |
dir: BlockDir.EAST, | |
style: style | |
}); | |
continue; | |
} | |
blockData.push({ | |
xOffset: options.xOffset + (i - 1) - j, | |
yOffset: options.yOffset - (i - 1), | |
zOffset: options.zOffset + i, | |
shape: BlockShape.RAMP, | |
dir: BlockDir.SOUTH, | |
style: style | |
}); | |
} | |
for (var j = 0; j < i * 2; j++){ | |
if (j === 0 || j === ((i * 2) - 1)){ | |
continue; | |
} | |
blockData.push({ | |
xOffset: options.xOffset - i, | |
yOffset: options.yOffset - (i - 1), | |
zOffset: options.zOffset - (i - 1) + j, | |
shape: BlockShape.RAMP, | |
dir: BlockDir.EAST, | |
style: style | |
}); | |
} | |
} | |
} | |
break; | |
default: | |
break; | |
} | |
return blockData; | |
} | |
} | |
})(); | |
// Save blocks that we want to use later | |
Animation.saveBlock({ | |
shape: BlockShape.BOX, | |
dir: BlockDir.NORTH, | |
style: 26 // ocean, doesn't work atm | |
}, "ocean"); | |
// Save animation frame data | |
Animation.addFrame( | |
Animation.create(Animation.SHAPES.PYRAMID, { | |
xOffset: 0, | |
yOffset: 0, | |
zOffset: 0, | |
height: 1, | |
block: "ocean" | |
}) | |
); | |
Animation.addFrame( | |
Animation.create(Animation.SHAPES.PYRAMID, { | |
xOffset: 1, | |
yOffset: 1, | |
zOffset: 0, | |
height: 2, | |
block: { | |
shape: BlockShape.BOX, | |
dir: BlockDir.NORTH, | |
style: 26 | |
} | |
}) | |
); | |
Animation.addFrame( | |
Animation.create(Animation.SHAPES.PYRAMID, { | |
xOffset: 2, | |
yOffset: 0, | |
zOffset: 0, | |
height: 1, | |
block: { | |
shape: BlockShape.BOX, | |
dir: BlockDir.NORTH, | |
style: 26 | |
} | |
}) | |
); | |
Animation.addFrame( | |
Animation.create(Animation.SHAPES.PYRAMID, { | |
xOffset: 3, | |
yOffset: 1, | |
zOffset: 0, | |
height: 2, | |
block: { | |
shape: BlockShape.BOX, | |
dir: BlockDir.NORTH, | |
style: 26 | |
} | |
}) | |
); | |
Animation.addFrame( | |
Animation.create(Animation.SHAPES.PYRAMID, { | |
xOffset: 4, | |
yOffset: 0, | |
zOffset: 0, | |
height: 1, | |
block: { | |
shape: BlockShape.BOX, | |
dir: BlockDir.NORTH, | |
style: 26 | |
} | |
}) | |
); | |
// Animation.addFrame([{ | |
// x: 0, | |
// y: 0, | |
// z: 0, | |
// block: "ocean" | |
// }]); | |
// Animation.addFrame([{ | |
// x: 0, | |
// y: 0, | |
// z: 5, | |
// block: "ocean" | |
// }, { | |
// x: 0, | |
// y: 0, | |
// z: 4, | |
// block: "ocean" | |
// }]); | |
// Animation.addFrame([{ | |
// x: 0, | |
// y: 0, | |
// z: 4, | |
// block: "ocean" | |
// }, { | |
// x: 0, | |
// y: 0, | |
// z: 3, | |
// block: "ocean" | |
// }, { | |
// x: -1, | |
// y: 0, | |
// z: 3, | |
// block: "ocean" | |
// }, { | |
// x: 1, | |
// y: 0, | |
// z: 3, | |
// block: "ocean" | |
// }, { | |
// x: 0, | |
// y: 1, | |
// z: 3, | |
// block: "ocean" | |
// }, { | |
// x: 0, | |
// y: 0, | |
// z: 2, | |
// block: "ocean" | |
// }]); | |
// Animation.addFrame([{ | |
// x: 0, | |
// y: 0, | |
// z: 2, | |
// block: "ocean" | |
// }, { | |
// x: 0, | |
// y: 0, | |
// z: 1, | |
// block: "ocean" | |
// }]); | |
// Animation.addFrame([{ | |
// x: 0, | |
// y: 0, | |
// z: 0, | |
// block: "ocean" | |
// }]); | |
// onTick is called every frame (50-60 times per second). | |
export function onTick() { | |
Animation.setOrigin(getPos()); | |
Animation.play(); | |
} | |
export function onCollision(msg) { | |
cooldown(1); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment