Skip to content

Instantly share code, notes, and snippets.

@Aerodos12
Created February 21, 2018 23:01
Show Gist options
  • Save Aerodos12/60bc3c73b979e1224d8322f40b4d6ef0 to your computer and use it in GitHub Desktop.
Save Aerodos12/60bc3c73b979e1224d8322f40b4d6ef0 to your computer and use it in GitHub Desktop.
Intro/Tutorial scheme
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