Created
February 21, 2018 23:01
-
-
Save Aerodos12/60bc3c73b979e1224d8322f40b4d6ef0 to your computer and use it in GitHub Desktop.
Intro/Tutorial scheme
This file contains hidden or 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
local TweenService = game:GetService("TweenService") | |
local RunService = game:GetService("RunService") | |
local Players = game:GetService("Players") | |
local UserInputService = game:GetService("UserInputService") | |
local Settings = UserSettings() | |
local GameSettings = Settings.GameSettings | |
local LocalPlayer = Players.LocalPlayer | |
local IMAGE_INTRO_MOVE = "rbxasset://textures/ui/Input/IntroMove.png" | |
local IMAGE_INTRO_CAMERA = "rbxasset://textures/ui/Input/IntroCamera.png" | |
local IMAGE_INTRO_CAMERA_PINCH = "rbxasset://textures/ui/Input/IntroCameraPinch.png" | |
local IMAGE_DASHED_LINE = "rbxasset://textures/ui/Input/DashedLine.png" | |
local MIDDLE_TRANSPARENCIES = { | |
1 - 0.69, | |
1 - 0.50, | |
1 - 0.40, | |
1 - 0.30, | |
1 - 0.20, | |
1 - 0.10, | |
1 - 0.05 | |
} | |
local MOVE_CAMERA_THRESHOLD = 50 | |
local ParentFrame = nil | |
local ThumbstickFrame = nil | |
local StartImage, EndImage, MiddleImages = nil, nil, {} | |
local IntroMoveImage = nil | |
local IntroJumpImage = nil | |
local IntroJumpImageTap = nil | |
local IntroCameraImage = nil | |
local IntroCornerAnim = nil | |
local IntroDashedLine = nil | |
local GenericFadeTweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut) | |
local IntroMoveSpriteSize = 128 | |
local IntroMoveImageSize = 128 | |
local noThumbstickFrameFade = true | |
local function create(className) | |
return function(props) | |
local instance = Instance.new(className) | |
for key, val in pairs(props) do | |
if typeof(key) == "string" then | |
if key ~= "Parent" then | |
instance[key] = val | |
end | |
else | |
if typeof(val) == "Instance" then | |
val.Parent = instance | |
end | |
end | |
end | |
instance.Parent = props.Parent | |
return instance | |
end | |
end | |
local Intro = { | |
fadeThumbstick = nil, | |
fadeThumbstickFrame = nil, | |
didMoveThumbstick = false, | |
didJump = false, | |
didMoveCamera = false, | |
currentState = nil, | |
states = {}, | |
} | |
function Intro.setup(isBigScreen, parentFrame, thumbstickFrame, startImage, endImage, middleImages) | |
ParentFrame = parentFrame | |
ThumbstickFrame = thumbstickFrame | |
StartImage = startImage | |
EndImage = endImage | |
MiddleImages = middleImages | |
if isBigScreen then | |
IntroMoveImageSize = IntroMoveImageSize * 2 | |
end | |
IntroMoveImage = create("ImageLabel") { | |
Name = "IntroMoveAnimation", | |
BackgroundTransparency = 1, | |
Image = IMAGE_INTRO_MOVE, | |
AnchorPoint = Vector2.new(102/256, 55/256), | |
Position = UDim2.new(0.5, 0, 0.5, 0), | |
Size = UDim2.new(0, IntroMoveImageSize, 0, IntroMoveImageSize), | |
ImageRectOffset = Vector2.new(IntroMoveSpriteSize, IntroMoveSpriteSize), | |
ImageRectSize = Vector2.new(IntroMoveSpriteSize, IntroMoveSpriteSize), | |
ZIndex = 10, | |
Visible = false, | |
Parent = EndImage | |
} | |
IntroJumpImage = create("ImageLabel") { | |
Name = "IntroJumpAnimation", | |
BackgroundTransparency = 1, | |
AnchorPoint = Vector2.new(102/256, 55/256), | |
Position = UDim2.new(0.75, 0, 0.25, 0), | |
Image = IMAGE_INTRO_MOVE, | |
ImageRectOffset = Vector2.new(0, 0), | |
ImageRectSize = Vector2.new(IntroMoveSpriteSize, IntroMoveSpriteSize), | |
ZIndex = 10, | |
Visible = false, | |
Parent = ThumbstickFrame | |
} | |
IntroJumpImageTap = create("ImageLabel") { | |
Name = "IntroJumpTapAnimation", | |
BackgroundTransparency = 1, | |
Image = IMAGE_INTRO_MOVE, | |
Position = UDim2.new(0, 0, 0, 0), | |
AnchorPoint = Vector2.new(0, 0), | |
Size = UDim2.new(1, 0, 1, 0), | |
ImageTransparency = 1, | |
ImageRectOffset = Vector2.new(IntroMoveSpriteSize, 0), | |
ImageRectSize = Vector2.new(IntroMoveSpriteSize, IntroMoveSpriteSize), | |
ZIndex = 10, | |
Visible = false, | |
Parent = IntroJumpImage | |
} | |
IntroCameraImage = create("ImageLabel") { | |
Name = "IntroCameraDragAnimation", | |
BackgroundTransparency = 1, | |
Image = IMAGE_INTRO_MOVE, | |
ImageRectOffset = Vector2.new(0, IntroMoveSpriteSize), | |
ImageRectSize = Vector2.new(IntroMoveSpriteSize, IntroMoveSpriteSize), | |
Position = UDim2.new(0.75, 0, -0.6, 0), | |
Size = UDim2.new(0, IntroMoveImageSize, 0, IntroMoveImageSize), | |
AnchorPoint = Vector2.new(0.5, 0.5), | |
ZIndex = 10, | |
Visible = false, | |
Parent = ThumbstickFrame | |
} | |
IntroPinchImage = create("ImageLabel") { | |
Name = "IntroCameraPinchAnimation", | |
BackgroundTransparency = 1, | |
Image = IMAGE_INTRO_CAMERA_PINCH, | |
ImageRectOffset = Vector2.new(0, 0), | |
ImageRectSize = Vector2.new(IntroMoveSpriteSize, IntroMoveSpriteSize), | |
Position = UDim2.new(1, 0, -1, 0), | |
Size = UDim2.new(0, IntroMoveImageSize, 0, IntroMoveImageSize), | |
AnchorPoint = Vector2.new(1, 0), | |
Rotation = 50, | |
ZIndex = 10, | |
Visible = false, | |
Parent = ThumbstickFrame | |
} | |
IntroDashedLine = create("ImageLabel") { | |
Name = "DashedLine", | |
BackgroundTransparency = 1, | |
Position = UDim2.new(0, 0, 0, -5), | |
Size = UDim2.new(1, 0, 0, 10), | |
Image = IMAGE_DASHED_LINE, | |
ImageTransparency = 0.5, | |
ScaleType = Enum.ScaleType.Tile, | |
TileSize = UDim2.new(0, 64, 0, 10), | |
Visible = false, | |
Parent = ThumbstickFrame | |
} | |
end | |
function Intro.addState(stateName) | |
local state = {} | |
state.counter = 0 | |
Intro.states[stateName] = state | |
return state | |
end | |
function Intro.onCompleted() | |
--TODO: Remove this pcall when API is stable | |
pcall(function() GameSettings:SetOnboardingCompleted("DynamicThumbstick") end) | |
local fadeOut = TweenService:Create(IntroDashedLine, GenericFadeTweenInfo, { ImageTransparency = 1 }) | |
fadeOut:Play() | |
fadeOut.Completed:wait() | |
IntroDashedLine.Visible = false | |
end | |
function Intro.setState(newState) | |
if Intro.currentState == newState then return end | |
if Intro.currentState then | |
coroutine.wrap(function() Intro.currentState:stop() end)() | |
end | |
Intro.currentState = newState | |
Intro.currentState.counter = Intro.currentState.counter + 1 | |
Intro.currentState:start() | |
end | |
function Intro.repeatState() | |
if not Intro.currentState then return end | |
coroutine.wrap(function() Intro.currentState:stop() end)() | |
Intro.currentState.counter = Intro.currentState.counter + 1 | |
Intro.currentState:start() | |
end | |
function Intro.stop() | |
if not Intro.currentState then return end | |
Intro.currentState:stop() | |
Intro.currentState = nil | |
end | |
function Intro.onThumbstickMoveBegin() | |
if Intro.currentState == Intro.states.MoveThumbstick then | |
Intro.states.MoveThumbstick.startedMoving = true | |
local moveTween = Intro.states.MoveThumbstick.moveTween | |
if moveTween then | |
moveTween:Cancel() | |
end | |
end | |
end | |
function Intro.onThumbstickMoved(dist) | |
if Intro.currentState == Intro.states.MoveThumbstick then | |
if dist > 100 then | |
Intro.stop() | |
spawn(function() | |
wait(0.5) | |
while StartImage.ImageTransparency ~= 1 do | |
wait() | |
end | |
if Intro.states.MoveThumbstick.counter > 1 then | |
Intro.setState(Intro.states.Jump) | |
else | |
Intro.setState(Intro.states.MoveThumbstick) | |
end | |
end) | |
else | |
Intro.states.MoveThumbstick.startedMoving = false | |
local moveTween = Intro.states.MoveThumbstick.moveTween | |
if moveTween then | |
moveTween:Play() | |
end | |
end | |
end | |
end | |
function Intro.onJumped() | |
if Intro.currentState == Intro.states.Jump then | |
Intro.stop() | |
spawn(function() | |
wait(1) | |
if Intro.states.Jump.counter > 1 then | |
Intro.setState(Intro.states.MoveCamera) | |
else | |
Intro.setState(Intro.states.Jump) | |
end | |
end) | |
end | |
end | |
function Intro.onCameraMoved() | |
if Intro.currentState == Intro.states.MoveCamera then | |
wait(1) | |
Intro.setState(Intro.states.ZoomCamera) | |
end | |
end | |
function Intro.onCameraZoomed() | |
if Intro.currentState == Intro.states.ZoomCamera then | |
Intro.stop() | |
end | |
end | |
function Intro.play() | |
for _, state in pairs(Intro.states) do | |
state.counter = 0 | |
end | |
Intro.setState(Intro.states.MoveThumbstick) | |
end | |
Intro.addState("MoveThumbstick") do | |
function Intro.states.MoveThumbstick:start() | |
StartImage.Visible = true | |
EndImage.Visible = true | |
IntroMoveImage.Visible = true | |
IntroDashedLine.Visible = true | |
IntroDashedLine.ImageTransparency = 0.5 | |
self.startedMoving = false | |
StartImage.Position = UDim2.new(0.5, 0, 0.6, 0) | |
EndImage.Position = UDim2.new(0.5, 0, 0.6, 0) | |
local moveTweenTarget = UDim2.new(0.3, 0, -0.25, 0) | |
if Intro.states.MoveThumbstick.counter % 2 ~= 0 then | |
moveTweenTarget = UDim2.new(0.7, 0, -0.25, 0) | |
end | |
local moveTweenInfo = TweenInfo.new(1.5, Enum.EasingStyle.Quart, Enum.EasingDirection.InOut) | |
self.moveTween = TweenService:Create(EndImage, moveTweenInfo, { Position = moveTweenTarget }) | |
local moveFadeInfo = TweenInfo.new(0.15, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut) | |
local fadeOutTween = TweenService:Create(IntroMoveImage, moveFadeInfo, { ImageTransparency = 1 }) | |
local fadeInTween = TweenService:Create(IntroMoveImage, moveFadeInfo, { ImageTransparency = 0 }) | |
self.moveAnimActive = true | |
coroutine.wrap(function() | |
while Intro.currentState == self do | |
if not self.startedMoving then | |
if not noThumbstickFrameFade then | |
Intro.fadeThumbstickFrame(moveTweenInfo.Time, 0.05) | |
end | |
EndImage.Position = UDim2.new(0.5, 0, 0.6, 0) | |
self.moveTween:Play() | |
Intro.fadeThumbstick(true) | |
fadeInTween:Play() | |
self.moveTween.Completed:wait() | |
if Intro.currentState == self then | |
Intro.fadeThumbstick(false) | |
fadeOutTween:Play() | |
fadeOutTween.Completed:wait() | |
wait(0.5) | |
end | |
else | |
wait() | |
end | |
end | |
end)() | |
end | |
function Intro.states.MoveThumbstick:stop() | |
self.moveTween:Cancel() | |
IntroMoveImage.Visible = false | |
if self.iconOptConn then | |
self.iconOptConn:disconnect() | |
self.iconOptConn = nil | |
end | |
end | |
end | |
Intro.addState("Jump") do | |
function Intro.states.Jump:start() | |
IntroJumpImage.Visible = true | |
IntroJumpImageTap.Visible = true | |
local jumpImageBaseSize = IntroMoveImageSize | |
IntroJumpImage.Size = UDim2.new(0, jumpImageBaseSize * 1.5, 0, jumpImageBaseSize * 1.25) | |
IntroJumpImageTap.ImageTransparency = 1 | |
local fadeInInfo = TweenInfo.new(0.15, Enum.EasingStyle.Quint, Enum.EasingDirection.InOut) | |
local fadeOutInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut) | |
self.fadeHandIn = TweenService:Create(IntroJumpImage, fadeInInfo, { ImageTransparency = 0, Size = UDim2.new(0, jumpImageBaseSize, 0, jumpImageBaseSize * 0.95) }) | |
self.fadeHandOut = TweenService:Create(IntroJumpImage, fadeOutInfo, { ImageTransparency = 0.25, Size = UDim2.new(0, jumpImageBaseSize * 1.25, 0, jumpImageBaseSize * 1.25) }) | |
self.fadeTapIn = TweenService:Create(IntroJumpImageTap, fadeInInfo, { ImageTransparency = 0 }) | |
self.fadeTapOut = TweenService:Create(IntroJumpImageTap, fadeOutInfo, { ImageTransparency = 1 }) | |
coroutine.wrap(function() | |
while Intro.currentState == self do | |
self.fadeHandIn:Play() | |
IntroJumpImageTap.ImageTransparency = 1 | |
if self.iconOptConn then | |
self.iconOptConn:disconnect() | |
self.iconOptConn = nil | |
end | |
wait(self.fadeHandIn.Completed:wait()) | |
if not noThumbstickFrameFade then | |
Intro.fadeThumbstickFrame(fadeOutInfo.Time, 0) | |
end | |
IntroJumpImageTap.ImageTransparency = 0 | |
self.fadeHandOut:Play() | |
self.fadeTapOut:Play() | |
self.fadeHandOut.Completed:wait() | |
end | |
end)() | |
end | |
function Intro.states.Jump:stop() | |
IntroJumpImage.Visible = false | |
IntroJumpImageTap.Visible = false | |
end | |
end | |
Intro.addState("MoveCamera") do | |
function Intro.states.MoveCamera:start() | |
IntroCameraImage.Visible = true | |
local swipeInfo = TweenInfo.new(1, Enum.EasingStyle.Quint, Enum.EasingDirection.InOut) | |
local swipeTweenLeft = TweenService:Create(IntroCameraImage, swipeInfo, { Position = UDim2.new(0.25, 0, -0.6, 0) }) | |
local swipeTweenRight = TweenService:Create(IntroCameraImage, swipeInfo, { Position = UDim2.new(0.75, 0, -0.6, 0) }) | |
local camera = workspace.CurrentCamera | |
local cameraLookStart = camera.CFrame.lookVector | |
coroutine.wrap(function() | |
while Intro.currentState == self do | |
swipeTweenLeft:Play() | |
swipeTweenLeft.Completed:wait() | |
swipeTweenRight:Play() | |
swipeTweenRight.Completed:wait() | |
end | |
end)() | |
local function isInCameraArea(touchPos) | |
--if isPortraitMode then | |
if touchPos.Y < ThumbstickFrame.AbsolutePosition.Y then | |
return true | |
end | |
--end | |
end | |
local touchObj = nil | |
local recordedMovement = Vector3.new() | |
self.onInputBeganConn = UserInputService.InputBegan:Connect(function(inputObj, wasProcessed) | |
if inputObj.UserInputType == Enum.UserInputType.Touch and isInCameraArea(inputObj.Position) and not wasProcessed then | |
touchObj = inputObj | |
end | |
end) | |
self.onInputChangedConn = UserInputService.InputChanged:Connect(function(inputObj, wasProcessed) | |
if inputObj == touchObj then | |
recordedMovement = recordedMovement + inputObj.Delta | |
if recordedMovement.magnitude > MOVE_CAMERA_THRESHOLD then | |
IntroCameraImage.Visible = false | |
end | |
end | |
end) | |
self.onInputEndedConn = UserInputService.InputEnded:Connect(function(inputObj, wasProcessed) | |
if inputObj == touchObj then | |
touchObj = nil | |
if recordedMovement.magnitude > MOVE_CAMERA_THRESHOLD then --todo: make this number a constant | |
Intro.onCameraMoved() | |
end | |
end | |
end) | |
end | |
function Intro.states.MoveCamera:stop() | |
if self.iconOptConn then | |
self.iconOptConn:disconnect() | |
self.iconOptConn = nil | |
end | |
IntroCameraImage.Visible = false | |
end | |
end | |
Intro.addState("ZoomCamera") do | |
function Intro.states.ZoomCamera:start() | |
IntroPinchImage.Visible = true | |
local camera = workspace.CurrentCamera | |
local zoomStart = (camera.Focus.p - camera.CFrame.p).magnitude | |
coroutine.wrap(function() | |
while Intro.currentState == self do | |
IntroPinchImage.ImageRectOffset = Vector2.new(0, 0) | |
wait(0.75) | |
IntroPinchImage.ImageRectOffset = Vector2.new(128, 0) | |
wait(0.25) | |
end | |
end)() | |
coroutine.wrap(function() | |
while Intro.currentState == self do | |
local zoom = (camera.Focus.p - camera.CFrame.p).magnitude | |
if math.abs(zoom - zoomStart) > 3 then | |
Intro.onCameraZoomed() | |
end | |
wait() | |
end | |
end)() | |
end | |
function Intro.states.ZoomCamera:stop() | |
IntroPinchImage.Visible = false | |
Intro.onCompleted() | |
end | |
end | |
return Intro |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment