Hello everyone I want to experiment with a gradius style game. The problem I'm facing is concerning the options. In any other setting I'd store the ship's position over the last x frames in an array updating only if the ship actually moves. Updating the option would mean setting it's position to an earlier ship position received from this array. As Unity works with time and a non-fixed framerate I fear this approach won't work. This could take up way too much memory and would cause a delayed lag effect if for some reason the framerate drops at a certain point during gameplay (the options would experience this lag a bit later). Does anyone have a suggestion as to how to tackle this problem? Thanks in advance.
Found the answer by doing some tinkering. I'm working with 2d local positions (z is fixed). I just realized this code doesn't need to be global and would be better if put on the ship itself, but this should be sufficient information for people facing the same problem. Code (csharp): // Option data // Max amount of options static var maxOptionCount : int = 3; // How many frames is the option behind the ship? static var optionFrameDelay : int = 40; // FPS to store in memory static var posMemoryFps : int = 100; // Amount of frames to store in memory static var storeFrameCount : int = (maxOptionCount+1) * optionFrameDelay; // Positon memory storage (player,frame,axis) static var shipPositions : float[,,] = new float[2,storeFrameCount,2]; // Amount of time the ship spent moving static var shipMoveTime : float = 0.0; // Retrieves the position for the nth option relative to the player's ship (defined by dist) public static function getOptionPos(player, dist) { // Distance in frames var frameDist = dist * optionFrameDelay; // Return array containing an x and y position var returnPos : float[] = new float[2]; returnPos[0] = shipPositions[player,frameDist,0]; returnPos[1] = shipPositions[player,frameDist,1]; return returnPos; } // Empties the option memory public static function resetShipPosMemory(player,x,y) { shipMoveTime = 0.0; // By default all positions are the current position of the ship for (var pos = 0; pos < storeFrameCount; pos++) { shipPositions[player,pos,0] = x; shipPositions[player,pos,1] = y; } } // Adds a new position to the storage public static function addShipPos(player,x,y) { // Shift all ship positions one to the right for (var pos = storeFrameCount - 1; pos > 0; pos--) { shipPositions[player,pos,0] = shipPositions[player,pos-1,0]; shipPositions[player,pos,1] = shipPositions[player,pos-1,1]; } // Put the new position up front shipPositions[player,0,0] = x; shipPositions[player,0,1] = y; } public static function getDeltaPos(prevX, prevY, currX, currY, part) { var deltaPos : float[] = new float[2]; // Difference between the positions over time diffPosX = (currX - prevX) * part; diffPosY = (currY - prevY) * part; // Add the difference to the previous position (subtract if negative) deltaPos[0] = prevX + diffPosX; deltaPos[1] = prevY + diffPosY; return deltaPos; } public static function setShipPositionMemory(player,deltaTime,x,y) { // Store previous time locally var prevTime = shipMoveTime; // Update last move time globally shipMoveTime += deltaTime; // Does the x/y differ from the previous? Then we moved if (x != shipPositions[player,0,0] || y != shipPositions[player,0,1]) { // The difference between both times must be at least 1 posMemoryFps unit var posMemoryFrameTime : float = 1.0 / posMemoryFps; // Framenumbers rounded down for the previous and the current position var prevFrameNo : int = Mathf.FloorToInt(prevTime/posMemoryFrameTime); var thisFrameNo : int = Mathf.FloorToInt(shipMoveTime/posMemoryFrameTime); // If they do not match, we've moved on at least 1 frame if (prevFrameNo < thisFrameNo) { // In case of low game fps the framecount might be bigger than one var frameCount = thisFrameNo - prevFrameNo; // Get the last stored ship position var lastShipX = shipPositions[player,0,0]; var lastShipY = shipPositions[player,0,1]; // Add one ship position for each frame for (var deltaFrame = 0; deltaFrame < frameCount; deltaFrame++) { if (deltaFrame == frameCount-1) { addShipPos(player,x,y); } else { // Time elapsed between the keyframe and the current time var moveDeltaTime : float = shipMoveTime - ((prevFrameNo + deltaFrame) * posMemoryFrameTime); // Float between 0 and 1 to determine the percentage of the frame time relative to the current time var movePart : float = (posMemoryFrameTime * (deltaFrame+1)) / moveDeltaTime; // Calculated frame position var framePosition : float[] = getDeltaPos(lastShipX,lastShipY,x,y,movePart); // Store the frame position addShipPos(player,framePosition[0],framePosition[1]); } } } } } In the movement script you probably already have for the ship add the following: Code (csharp): #pragma strict var player : int = 0; function Start() { globals.resetShipPosMemory(player, transform.localPosition.x, transform.localPosition.y); } function Update () { // ..... your movement code here ...... // // Store the ship's position for following options globals.setShipPositionMemory(player, Time.deltaTime, transform.localPosition.x, transform.localPosition.y); } And this is for the option: Code (csharp): #pragma strict var player : int = 0; var distanceFromShip : int = 1; function Start () { } function Update () { var position : float[] = globals.getOptionPos(player,distanceFromShip); transform.localPosition = Vector3(position[0], position[1], 0); } Apart from the obvious fact that this doesn't need to be global, Any constructive criticism would be welcome. I've still only got about a week of Unity3d experience
Gradius style Options. This only worked when I assigned the followTransform to what each option is following. So the first 'option' is following the player, the 2nd 'option' is following the 1st 'option' etc... using System.Collections.Generic; using UnityEngine; public class OptionMovement : MonoBehaviour { public Transform followTransform; [SerializeField] int optionFrameDelay = 30; //list of positions the player took private List<Vector3> positionList = new List<Vector3>(); private void Start() { for (int i = 0; i < optionFrameDelay; i++) { positionList.Add(followTransform.position); } } void Update() { //if the player position changed if (followTransform.hasChanged) { //Follow the player positionList.Add(followTransform.position); if (positionList.Count > optionFrameDelay) { positionList.RemoveAt(0); transform.position = positionList[0]; } followTransform.hasChanged = false; } } }