Search Unity

Gradius style options - follow

Discussion in 'Scripting' started by Smots, Apr 9, 2013.

  1. Smots

    Smots

    Joined:
    Apr 4, 2013
    Posts:
    6
    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.
     
    Last edited: Apr 9, 2013
  2. Smots

    Smots

    Joined:
    Apr 4, 2013
    Posts:
    6
    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):
    1.  
    2. // Option data
    3. // Max amount of options
    4. static var maxOptionCount : int = 3;
    5. // How many frames is the option behind the ship?
    6. static var optionFrameDelay : int = 40;
    7.  
    8. // FPS to store in memory
    9. static var posMemoryFps : int = 100;
    10. // Amount of frames to store in memory
    11. static var storeFrameCount : int = (maxOptionCount+1) * optionFrameDelay;
    12. // Positon memory storage (player,frame,axis)
    13. static var shipPositions : float[,,] = new float[2,storeFrameCount,2];
    14. // Amount of time the ship spent moving
    15. static var shipMoveTime : float = 0.0;
    16.  
    17. // Retrieves the position for the nth option relative to the player's ship (defined by dist)
    18. public static function getOptionPos(player, dist) {
    19.     // Distance in frames
    20.     var frameDist = dist * optionFrameDelay;
    21.     // Return array containing an x and y position
    22.     var returnPos : float[] = new float[2];
    23.     returnPos[0] = shipPositions[player,frameDist,0];
    24.     returnPos[1] = shipPositions[player,frameDist,1];
    25.     return returnPos;
    26. }
    27.  
    28. // Empties the option memory
    29. public static function resetShipPosMemory(player,x,y) {
    30.     shipMoveTime = 0.0;
    31.     // By default all positions are the current position of the ship
    32.     for (var pos = 0; pos < storeFrameCount; pos++) {
    33.         shipPositions[player,pos,0] = x;
    34.         shipPositions[player,pos,1] = y;
    35.     }
    36. }
    37.  
    38. // Adds a new position to the storage
    39. public static function addShipPos(player,x,y) {
    40.     // Shift all ship positions one to the right
    41.     for (var pos = storeFrameCount - 1; pos > 0; pos--) {
    42.         shipPositions[player,pos,0] = shipPositions[player,pos-1,0];
    43.         shipPositions[player,pos,1] = shipPositions[player,pos-1,1];
    44.     }
    45.     // Put the new position up front
    46.     shipPositions[player,0,0] = x;
    47.     shipPositions[player,0,1] = y;
    48. }
    49.  
    50. public static function getDeltaPos(prevX, prevY, currX, currY, part) {
    51.     var deltaPos : float[] = new float[2];
    52.     // Difference between the positions over time
    53.     diffPosX = (currX - prevX) * part;
    54.     diffPosY = (currY - prevY) * part;
    55.     // Add the difference to the previous position (subtract if negative)
    56.     deltaPos[0] = prevX + diffPosX;
    57.     deltaPos[1] = prevY + diffPosY;
    58.    
    59.     return deltaPos;
    60. }
    61.  
    62. public static function setShipPositionMemory(player,deltaTime,x,y) {
    63.     // Store previous time locally
    64.     var prevTime = shipMoveTime;
    65.     // Update last move time globally
    66.     shipMoveTime += deltaTime;
    67.     // Does the x/y differ from the previous? Then we moved
    68.     if (x != shipPositions[player,0,0] || y != shipPositions[player,0,1]) {
    69.         // The difference between both times must be at least 1 posMemoryFps unit
    70.         var posMemoryFrameTime : float = 1.0 / posMemoryFps;
    71.         // Framenumbers rounded down for the previous and the current position
    72.         var prevFrameNo : int = Mathf.FloorToInt(prevTime/posMemoryFrameTime);
    73.         var thisFrameNo : int = Mathf.FloorToInt(shipMoveTime/posMemoryFrameTime);
    74.         // If they do not match, we've moved on at least 1 frame
    75.         if (prevFrameNo < thisFrameNo) {
    76.             // In case of low game fps the framecount might be bigger than one
    77.             var frameCount = thisFrameNo - prevFrameNo;
    78.             // Get the last stored ship position
    79.             var lastShipX = shipPositions[player,0,0];
    80.             var lastShipY = shipPositions[player,0,1];
    81.             // Add one ship position for each frame
    82.             for (var deltaFrame = 0; deltaFrame < frameCount; deltaFrame++) {
    83.                 if (deltaFrame == frameCount-1) {
    84.                     addShipPos(player,x,y);
    85.                 } else {
    86.                     // Time elapsed between the keyframe and the current time
    87.                     var moveDeltaTime : float = shipMoveTime - ((prevFrameNo + deltaFrame) * posMemoryFrameTime);
    88.                     // Float between 0 and 1 to determine the percentage of the frame time relative to the current time
    89.                     var movePart : float = (posMemoryFrameTime * (deltaFrame+1)) / moveDeltaTime;
    90.                     // Calculated frame position
    91.                     var framePosition : float[] = getDeltaPos(lastShipX,lastShipY,x,y,movePart);
    92.                    
    93.                     // Store the frame position
    94.                     addShipPos(player,framePosition[0],framePosition[1]);
    95.                 }
    96.             }
    97.         }
    98.     }
    99. }
    100.  
    In the movement script you probably already have for the ship add the following:
    Code (csharp):
    1.  
    2. #pragma strict
    3. var player : int = 0;
    4.  
    5. function Start() {
    6.     globals.resetShipPosMemory(player, transform.localPosition.x, transform.localPosition.y);
    7. }
    8.  
    9. function Update () {
    10.  
    11.     // ..... your movement code here ...... //
    12.  
    13.     // Store the ship's position for following options
    14.     globals.setShipPositionMemory(player, Time.deltaTime, transform.localPosition.x, transform.localPosition.y);
    15. }
    16.  
    And this is for the option:
    Code (csharp):
    1.  
    2. #pragma strict
    3.  
    4. var player : int = 0;
    5. var distanceFromShip : int = 1;
    6.  
    7. function Start () {
    8.  
    9. }
    10.  
    11. function Update () {
    12.     var position : float[] = globals.getOptionPos(player,distanceFromShip);
    13.     transform.localPosition = Vector3(position[0], position[1], 0);
    14. }
    15.  
    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
     
  3. Beta4

    Beta4

    Joined:
    Nov 6, 2014
    Posts:
    34
    Can someone translate this to C#?
     
  4. DrumColby

    DrumColby

    Joined:
    Apr 10, 2021
    Posts:
    1
    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;
    }
    }
    }