(终极第一人称射击文档)

    © 强制保留所有权利。

OpsiveLogoBlack.png

目录

介绍

试着玩一下演示项目

演示项目的操控方法

开始入门

开始尝试一下演示项目

天空城(Sky City)

明了的场景示例(CleanScene)

示例场景1(DemoScene1)

示例场景2(DemoScene2)

示例场景3(DemoScene3)

在你的项目中使用简单的玩家预制组件(player prefabs)

你应该知道的一些重要的概念

第一人称组件(FP components)

状态(States)

事件(Events)

编辑器的使用

调整数值

在游戏和编辑器之间切换

文本资源导航

要时刻注意控制台输出的日志

脚本

初学者

熟练工

代码注释

为啥使用 "vp_" 这个文件前缀名

从头创建一个 FPS 角色

基础设置

添加武器

调整武器位置

添加武器摄像头

添加子弹(投射体 projectile)

调整后坐力(recoil 反冲,后退,退缩,反跳,跳回,反冲力)

你要知道的动画相关的概念

弹力(Springs)

正弦运动(Bob 上下摆动)

噪声(Noise)

动画(Animations)

定时器 or 计时器(Timers)

控制器(Controller)

原动力(Motor)

加速度(Acceleration)

阻尼(Damping)

风速(Air Speed)

斜坡增速(Slope Speed Up)

斜坡减速(Slope Speed Down)

自由飞行(Free Fly)

跳跃(Jump)

力(Force)

阻尼力(Force Damping)

力的保持(Force (Hold))

阻尼力的保持(Force Damping (Hold))

物理相关(Physics)

阻尼力(Force Damping)

推力(Push Force)

修正重力(Gravity Modifier)

斜坡滑动限制(Slope Slide Limit)

斜坡滑动性(Slope Slidiness)

墙壁反弹(Wall Bounce)

墙壁摩擦(Wall Friction)

碰撞触发器(Has collision trigger)

摄像机相关

鼠标(Mouse)

灵敏度(Sensitivity)

平滑度(Smooth Steps)

平滑权重(Smooth Weight)

加速度(Acceleration)

加速度阈值(Acceleration Threshold)

渲染(Rendering)

视野(Field of View)

阻尼变焦(Zoom Damping)

禁用 VR 模块

位置弹簧(Position Spring)

偏移

地面限制

弹簧硬度(Spring Stiffness)

弹簧阻尼(Spring Damping)

弹簧2强度(Spring2 Stiffness)

弹簧2阻尼(Spring2 Damping)

跌落时重心下降(Kneeling)

跪幅度(Kneeling Softness)

地震参数(Earthquake Factor)

旋转(Rotation)

仰角俯角极限(Pitch Limit)

水平角度极限(Yaw Limit)

跌落时重心下降(Kneeling)

跪幅度(Kneeling Softness)

扫射幅度(Strafe Roll)

地震参数(Earthquake Factor)

抖动(Shake)

速度(Speed)

振幅(Amplitude)

上下摆动(Bob)

等级(Rate)

振幅(Amplitude)

阈值(Step Threshold)

输入速度刻度(Input Velocity Scale 目前难以理解)

最大输入速度(Max Input Velocity 目前难以理解)

需要地面接触点(Require ground contact)

武器

在 3D 素材包中定位模型

避免相机裁剪(Avoiding camera clipping)

选择模型武器穿透解决方案(Choosing a world intersection solution)

1. 武器相机(1. Weapon Camera)

2. 回缩(2. Retraction)

渲染(Rendering)

武器预制组件(Weapon Prefab)

视野(Field of View)

阻尼变焦(Zoom Damping)

剪切平面(Clipping Planes)

Z轴比例(Z Scale)

弹簧位置(Position Springs)

偏移(Offset)

出口偏移(Exit Offset)

轴点 or 参照点 or 中心点(Pivot)

轴点 or 参照点 or 中心点的硬度(Pivot Stiffness)

轴点 or 参照点 or 中心点的阻尼(Pivot Damping)

显示轴点 or 参照点 or 中心点的(Show Pivot)

弹簧硬度(Spring Stiffness)

弹簧阻尼(Spring Damping)

弹簧2硬度(Spring2 Stiffness)

弹簧2阻尼(Spring2 Damping)

跌落时重心下降(Kneeling)

跌落时重心下降柔性参数(Kneeling Softness)

跌落回缩(Fall Retract)

行走滑动(Walk Sliding)

输入速度刻度(Input Velocity Scale 目前难以理解)

最大输入速度(Max Input Velocity 目前难以理解)

弹簧旋转 or 弹性旋转(Rotation Springs)

偏移量(Offset)

出口偏移(Exit Offset)

轴点 or 参照点 or 中心点(Pivot)

轴点 or 参照点 or 中心点的硬度(Pivot Stiffness)

轴点 or 参照点 or 中心点的阻尼(Pivot Damping)

显示轴点 or 参照点 or 中心点的(Show Pivot)

弹簧硬度(Spring Stiffness)

弹簧阻尼(Spring Damping)

弹簧2硬度(Spring2 Stiffness)

弹簧2阻尼(Spring2 Damping)

跌落时重心下降(Kneeling)

跌落时重心下降柔性参数(Kneeling Softness)

Look Sway

Strafe Sway

Fall Sway

Slope Sway

Input Rotation Scale

Max Input Rotation

回缩(Retraction)

回缩指南(Retraction tutorial)

距离(Distance)

偏移量(Offset)

位置返回常规状态速度(Relax Speed)

震动(Shake)

速度(Speed)

振幅 幅度(Amplitude)

上下摆动(Bob)

等级 比率(Rate)

振幅 幅度(Amplitude)

输入速度刻度(Input Velocity Scale 目前难以理解)

最大输入速度(Max Input Velocity 目前难以理解)

Require ground contact

Step

Min Velocity

Step Softness

Position Force

Rotation Force

Force Scale

Position Balance

Rotation Balance

声音(Sound)

Wield

Unwield

动画(Animation)

Wield

Unwield

Ambient

Ambient Interval

射击相关(Shooters)

Projectile

Firing Rate

Tap Firing Rate

预制体 预设体 预制组件(Prefab)

Scale

Count

Spread

Spawn Delay

Motion

后坐力位置(Position Recoil)

后坐力角度(Rotation Recoil)

Rotation Recoil Dead Zone

Position Reset

Rotation Reset

Position Pause

Rotation Pause

空弹开火后坐力(Dry Fire Recoil)

后坐力延迟(Recoil Delay)

枪炮口的闪光(Muzzle Flash)

预制体 预设体 预制组件(Prefab)

Position

Scale

Fade Speed

枪炮口的闪光(Muzzle Flash) Delay

Show Muzzle Flash

Shell

预制体 预设体 预制组件(Prefab)

Scale

弹射位置(Eject Position)

弹射方向(Eject Direction)

弹射速度(Eject Velocity)

弹射线路(Eject Spin)

弹射延迟(Eject Delay)

声音(Sound)

开火(Fire)

空弹开火(Dry Fire)

Fire Pitch

Fire Sound Delay

动画(Animation)

火焰(Fire)

近战攻击(Melee Attacks)

Tutorial (Basic)

The quickest way to set up a new melee weapon

Making adjustments

System Walkthrough

Weapon poses

Attack states

The melee attack sequence

Types of states

Pull

Swing

Attack

Default

Tutorial (Advanced)

Overview

1. Decide how the weapon should move

2. Create the Pull state

3. Create the Swing state

4. Assign the states to the weapon component

5. Create the attack script

6. Create an Attack state

7. Test the attack in-game

8. Tweak the swing motion

9. Tweak the recoil force

10. Tweak the physics force

Debug objects

角色身体(Player Body)

Features Overview

Body animator with headlook

Full body awareness

3rd person camera view

Hand-aiming & recoil

Ragdoll handling

Player Body Setup

Introduction

The "Body" child object

"Weapons" vs. "weapon props"

Good to know for Artists

Good to know for Scripters

Tutorials

Setting up a basic, ragdolled player body

Enabling animation, headlook and ragdoll handler

Removing head clipping and extra arms

Adding weapon props for 3rd person

Adjusting the position and rotation of weapon props

Defining spawnpoints for muzzleflashes and shell casings

枪炮口的闪光(Muzzle Flash)

Shell ejection

Re-using weapon groups

Calibrating 3rd person weapon aim

Preparation checklist

Calibration steps

Adjusting 3rd person Recoil

Head & Arm materials setup

Anatomy of a player body

1) The main Body object, childed to the root player gameobject

Components

2) The Skinned Mesh Renderer

3) The "Lowest Spine Bone", assigned to slot in the bodyanimator (1)

4) The "Head Bone" assigned to slot in the bodyanimator (1)

5) Right hand gameobject (parent of 3rd person weapons)

6) The Weapon Group

7) 3rd Person Weapon Models

Mecanim Reference

Upper and lower body split

Full body animations

State machines

Lower Body

Upper Body (main)

Upper Body -> Firearm

Upper Body -> Unarmed

Upper Body -> Melee Weapon

Parameters of the UFPSExampleAnimator

Floating point values

Booleans

Triggers

Integers (enum indices)

Supported animation content

Body scripting

Terminology

Local player

Remote player

Look Point

On a local player

On a remote player

Look Direction

In Local 1st person

In Local 3rd person / Remote players

IsFirstPerson

Recommended components and scripts to study

Where to find the 3rd person code?

Why is the bullet always fired from middle of camera in 1st person?

What exactly does the ragdoll handler do?

In case of funky headlook

Using the "Generate Remote Player" wizard for AI and multiplayer

Body Troubleshooting

Body related issues

The player model doesn't stick to the center of the charactercontroller, but rotates around it in a huge arc /

The player model walks away from the charactercontroller

My ragdoll keeps falling over backwards, but I want it to fall over forwards

My remote player or 3rd person player starts swiveling around its hip like crazy

My character is invisible and won't move. Upon closer inspection its body floats far away in the air and wobbles about strangely

The camera shakes violently when I move

The local player starts stopping, stuttering or jumping erratically high up in the air for no apparent reason, especially when moving

Headlook is weird somehow: head tilts to / rests on shoulder or looks in wrong direction

Weapon related issues

I have assigned a 3rd person weapon to the hand bone of my character and positioned it correctly but it won't appear in-game

When I aim or shoot in 3rd person, the hand of my character points in a wrong / unnatural direction

When I calibrate weapon aim, the next time I start the game it's broken

I am building a new player based on an old player prefab. The old weapons are hovering in front of me even though i have removed them from the FPcamera

Firearm shells fly off at an extremely high forward or sideways velocity when I'm moving and shooting

预设(Presets)

Load & Save

Save Tweaks

状态(States)

Creating a new state

Activating and deactivating states

State order

The Default state

State blocking

Deleting a state

Removing a preset

Persist play mode changes

抛射体 子弹(Projectiles)

Anatomy of a bullet prefab

Anatomy of a bullet hole decal prefab

Creating a new bullet type

Disabling quad raycasts per-projectile

Making bullets ignore triggers

Spawning certain impact effects such as blood on enemies

Preventing decals from attaching to enemies

枪炮口的闪光(Muzzle Flash)es

Creating a MuzzleFlash prefab from scratch

弹壳(Shells)

Creating a Shell prefab from scratch

Parameters

Life Time

Persistence

Bounce Sounds

玩家伤害处理(Player Damage Handler)

Parameters

Health

DeathEffect

MinDeathDelay & MaxDeathDelay

Respawns

MinRespawnTime & MaxRespawnTime

RespawnCheckRadius

RespawnSound

库存 背包(Inventory)

Basics

Item Scripts

vp_PIayerInventory

vp_ItemIdentifier

vp_ItemPickup

Item Types

Item

UnitBank

Unit

Adding the Inventory

Enabling a weapon for inventory use

Step 1/2: Declare an ItemType for your weapon

Step 2/2: Add an Item Identifier to the FPS weapon

Creating an Item Pickup

Setting the Start Weapon

Limiting inventory capacity

Limit specific items by Amount

Limit items by Volume or Weight

Unlimited items and ammo

Setting zero item restrictions

Setting unlimited ammo & items

Item ID

Item Identifier ID logic

爆炸(Explosions)

Spawning an Explosion from script

Parameters

Radius

Force

UpForce

Damage

CameraShake

DamageMethodName

SoundMinPitch & SoundMaxPitch

FXPrefabs

运动平台(Moving Platforms)

General requirements

Assigning the MovingPlatform layer

Moving platform tutorial

Path

Type

PingPong

Loop

Target

Waypoints

Auto Start Target

Return Delay

Cooldown

Direction

Movement

Interpolation Mode

EaseInOut

EaseIn

EaseOut

EaseOut2

Slerp

Lerp

速度(Speed)

Rotation

Interpolation mode

SyncToMovement

EaseOut

CustomEaseOut

CustomRotate

Physics

Push Force

Snap player to top

声音(Sound)

Start

Move

Waypoint

Stop

交互(Interaction)

Adding the Interact Manager

Parameters

Interact Distance

Max Interact Distance

Interactables

Parameters

Interact Type

Normal

Trigger

CollisionTrigger

Recipient Tags

Interact Distance

Interact Crosshair

Interact Text

Delay Showing Text

Climb Interactable

Parameters

Minimum Climb Speed

Climb Speed

Mount Speed

Distance To Climbable

Min Velocity To Climb

Climb Again Timeout

Mount Auto Rotate Pitch

Simple Climb

Dismount Force

Sounds

Audio Source

Mount Sounds

Dismount Sounds

Climbing Sound Speed

Climbing Pitch

Climbing Sounds

Grab Interactable

Parameters

On Grab Text

Grab State Crosshair

Footstep Force

跌落时重心下降(Kneeling)

Stiffness

震动速度(Shake Speed)

振动幅度(Shake Amplitude)

Throw Strength

Allow Throw Rotation

Burden

Max Collision Count

Carrying Offset

Camera Pitch Down Limit

Sounds Pitch

Grab Sounds

Drop Sounds

Throw Sounds

Platform Switch Interactable

Parameters

Switch Timeout

Platform

Audio Source

Switch Pitch Range

Switch Sounds

Switch Interactable

Parameters

Target

Target Message

Audio Source

Switch Pitch Range

Switch Sounds

地表系统(Surface System)

Features overview

Basic surface system logic

How does it all fit together?

Quick script overview

The SceneManager group

vp_SurfaceManager

vp_DecalManager

vp_PoolManager

ScriptableObjects

vp_SurfaceType

vp_SurfaceEffect

vp_ImpactEvent

Scripts that sit on scene objects

vp_SurfaceIdentifier

vp_PlayerFootFXHandler

vp_RigidbodyFX

Scripts that sit on effect prefabs

vp_FadingDecal

vp_ParticleFXPooler

Surface Manager

Texture Fallbacks

UV overlap

Default Fallbacks

Impact Event

Surface Type

Allow Decals

Dealing with stretched decals

Impact Events

Creating a new ImpactEvent

Fallback ImpactEvent

Surface Types

Recommended usage

Creating a new SurfaceType

ImpactFX

ImpactEvents and SurfaceEffects

Defining a fallback effect for when the ImpactType is unknown

Allow Footprints

Surface Effects

Creating a new SurfaceEffect

声音(Sound)s

Min & Max Pitch

Max One Per Frame

Objects

预制体 预设体 预制组件(Prefab)

Probability

Decal

Min & Max Scale

Allow Edge Overlap

Setting up a SurfaceEffect from scratch

Surface Identifiers

SurfaceType

Allow Decals

Surface ID

Enabling blood effects on the player

Decal Manager

Decal Limits

Total

Weathered

Placement Tests

Cleanup over time

Vertex Raycast Interval (sec) and Decals Per Batch

Instant quad corner test

Quad Raycast Range

Max Quad Raycasts

Allow Stretched Decals

Removal on Fail

Delay

Fadeout Speed

Insta-remove if offscreen

Fading Decals

Fadeout Delay

Fadeout Speed

Shrink Delay

Shrink Speed

Rotate Delay

Rotate Speed

Rotate Accelerate

Player Foot FX Handler

Footsteps

Mode

Detect Body Step

Fixed Time Interval

Interval mode with player body feet

Interval mode with "dummy" feet

Detect Camera Bob

Impact Event

Left Foot and Right Foot

Trigger Height

Sensitivity

Force Always Animate

Require Move Input

Verify Ground Contact

Jumping

Impact Event

Fall Impact

Impact Event

Threshold

Debug

Pause on every step

Mute local footsteps

State and Preset

Using a state to temporarily silence footsteps

Footstep Tutorials

Setting up a Foot FX Handler on your player

Tweaking AudioSources for footsteps

Recommended AudioSource settings for footstep sounds

Adding new footstep sounds to your game

Setting up footstep sounds for multiplayer

Using 'Muting local footsteps' for multiplayer testing

Setting footstep range

Making footsteps audible behind your back

Rigidbody FX

Impact Event

Impact Threshold

Min Camera Distance

Collision sounds

Making a Rigidbody emit SurfaceEffects on collision

Item pickup ground drop effects

Adding ragdoll drop effects

Advanced Surface System Topics

Surface Manager

Fallback logic

Limitations due to system architecture

Limitations due to Unity architecture

Footsteps

声音(Sound)s

Verify ground contact

Choosing a footstep detection mode

Detect Body Step

Pros

Cons

Detect Camera Bob

Pros

Cons

Fixed Time Interval

Pros

Cons

Bullets

Choosing a bullet script

vp_FXBullet

vp_Bullet

vp_HitscanBullet

Pooling

Why use vp_PoolManager?

Preventing bugs when pooling objects

Particle FX

地表系统故障修复(Surface System Troubleshooting)

Surface related

I have a level geometry whose material / shader does not have a texture. How to associate it with a surface?

My surface fallback does not work

I have put a vp_SurfaceIdentifier on an object but it does not seem to work

SurfaceEffects don't work on a static, multi-material / atlas map object

Bullet and decal related

Bullets make the wrong (or no) sound when hitting the player

Trouble getting decals to show on a uniformly scaled object

Trouble getting decals to show on a non-uniformly scaled object

In a standalone build, decals show up as stretched on a non-uniform, static object

Decals have not been removed when an objects respawns

Footstep related

Footsteps won't trigger in 'Detect Camera Bob' mode when I'm walking slowly, backwards or crouching

No footsteps / effects on terrain

VR

Introduction

What is the VR integration?

What is it not?

Input model

Requirements

Setup

Project Settings (IMPORTANT)

Install OVR Plugin

Script execution order

Demo scenes setup

UFPS_VR_Comfortable

Make these settings before play

'Comfortable' demo details

UFPS_VR_Moderate

Make these settings before play:

'Moderate' demo details

UFPS_VR_Intense

Make these settings before play

'Intense' demo details

Custom player and scene setup

Overview

Workflow

Scene root objects (not childed to each other)

Player Camera VR setting

Body

Adjustments

Footstep sounds

Camera adjustments

Procedural Motion

Death state

Reload state

Other unnecessary camera states

Weapons adjustments

Weapon states

回缩(Retraction)

Muzzle & shell eject points

Scene objects

VRMode gameobject

OVRCameraRig

Rigidbody interpolation

VR Scripts

vp_VRCameraManager

VR mode forced runtime changes

Procedural motion section

Snap Rotate section

SnapRotate

StepDegrees

MinDelay

vp_VRCrosshair

CrosshairPrefab

InteractIconPrefab

MaxDistance

RelaxSpeed

CrosshairMinDistance

InteractIconMinDistance

SurfaceOffset

HideOnZoom

vp_VRWeaponManager

RenderPitchLimit

HeadLookSway

InputSway

ForcedRetraction

vp_VRTeleporter

DirectionPointer

CursorPrefab

CursorFacesCamera

MaxTeleportDistance

MinTeleportInterval

FallImpactDistance

AllowJumping

vp_VRPainFlash

PlanePrefab

PainTexture

DeathTexture

距离(Distance)

Limitations and unsupported features in VR

General

UFPS features

VR Troubleshooting

General

The unity editor just crashes when I press play in VR

"There are X audio listeners in the scene. Please ensure there is always exactly one audio listener in the scene."

VR mode doesn't work / behaves oddly

"Hierarchy error. This component must be added to a gameobject with vp_Weapon components in child gameobjects."

Headset

Oculus Headset is not tracking

"Error (vp_VRCameraManager) 'CenterEyeAnchor' is not assigned."

My VR character suddenly seems taller or shorter than normal / I can't reach down to the pickups.

Input

I suddenly can't fire / interact / rotate

I can't fire in a standalone VR build

Snap rotating with the gamepad is unresponsive / slow

Snap rotating with the mouse is crazy sensitive

Rotating with the right gamepad stick is very sensitive / unsensitive

I can't move with the left gamepad stick but rotating with the right stick works

I can't rotate with the right gamepad stick but moving with the left stick works

I can't toss a grabbed rigidbody with the fire button using a gamepad

Interaction detection seems to be offset by a few decimeters in VR

The player slides a little when picking up items by pressing the Interact button in VR

FX

My player does not trigger footstep effects in VR

Performance

Rigidbody objects move with a stutter

Framerate micro stutter

图像效果(Image Effects)

Important notes

Rendering Path considerations

Forward Rendering

Deferred Lighting

Use Player Settings

Image FX compatibility notes

Crease

DepthOfField

EdgeDetectEffectNormals

GlobalFog

SSAOEffect

SunShafts

输入管理器(Input Manager)

Example scripting usage

Rebinding controls at runtime

Gamepads

Basic setup

Setting up basic gamepad buttons and axes for a new project

Setting up Left- and Right Trigger axes as buttons for a new project

Updating the Input Manager for an existing project (pre UFPS 1.6)

If you don't have a lot of custom bindings

If you have lots of custom bindings

Additional info

基础脚本(Basic scripting)

Accessing vp_LocalPlayer

Initialization

bool Exists

Refresh()

Position, Velocity, Angles and Directions

Vector3 Position

Vector2 Rotation

Vector3 BodyHeadLookDirection

Vector3 AimDirection

Physics and Velocity

Vector3 Velocity

float Velocity

AddForce(Vector3 force)

Move

Stop()

Teleportation

Teleport(Vector3 position, Vector2 rotation)

Teleport(float x, float y, float z, float pitch, float yaw)

Teleport(Vector3 position)

Teleport(float x, float y, float z)

Teleport(vp_SpawnPoint spawnPoint)

External Objects

Transform LookTransform

Transform GetLookTransform(float maxRange, int layerMask)

Transform Ground

Transform Platform

DismountPlatform

bool IsGrounded

Health and Death

Damage(float damage)

Damage(float damage, Transform source, vp_DamageInfo.DamageType type)

Damage(vp_DamageInfo damageInfo)

Die(float painHUDIntensity = 0.0f)

float Health

float MaxHealth

Weapons and Ammo

SetNextWeapon()

SetPrevWeapon()

SetWeaponByName(string gameObjectName)

SetWeaponByIndex(int index)

UnwieldCurrentWeapon

string CurrentWeaponName

int CurrentWeaponIndex

int CurrentAmmo

int CurrentMaxAmmo

int SpareAmmoForCurrentWeapon

Texture2D CurrentAmmoIcon

First- and Third Person

GoFirstPerson()

GoThirdPerson()

ToggleThirdPerson()

bool IsFirstPerson

Body Hierarchy

Collider Collider

Transform Head

Transform LeftFoot

Transform RightFoot

Effects

AudioClip DeathSound

vp_ImpactEvent FootstepFXImpactEvent

vp_ImpactEvent FallFXImpactEvent

vp_ImpactEvent JumpFXImpactEvent

Camera Shakes

CameraShake(float force = 0.5f, AudioClip audioClip = null, AudioSource audioSource = null)

GroundStomp(float force = 0.5f, AudioClip audioClip = null, AudioSource audioSource = null)

Input

EnableGameplayInput()

DisableGameplayInput()

ToggleGameplayInput()

EnableFreeLook()

DisableFreeLook()

Crosshair

ShowCrosshair

HideCrosshair

ToggleCrosshair

CrosshairTexture

Mouse Cursor

ShowMouseCursor()

ShowMouseCursorAndAllowMouseLook()

HideMouseCursor()

ToggleMouseCursor()

Multiplayer

bool IsMaster

Accessing components

EventHandler

Camera

Controller

InputManager

DamageHandler

WeaponHandler

库存 背包(Inventory)

Respawner

BodyAnimator

RagdollHandler

FootFXHandler

事件系统(Event system)

Introduction to the event system

Modularity

Performance

Understanding event driven code

Brief overview

Finding the lines that SEND an event

Finding the methods that LISTEN to an event

Event handler tutorial

Preparation

1. Declaring an event

2. Making the PlayerEventHandler available to the scripts

3. Registering a target script with the event handler

4. Adding an event listener

5. Sending an event

Event types

vp_Message

vp_Attempt

vp_Value

vp_Activity

Activity additional properties

MinPause

MinDuration

AutoDuration

Argument

Active

Start

Stop

Disallow

Binding states to Activities

Activity example flows

Crouch

Jump

Attack

What's the difference between an Activity and a State?

计时器 定时器(Timers)

Scheduling actions using vp_Timer.In

Iterations (repetition)

Intervals

Arguments

Multiple arguments

Delegates

Delegates with arguments

Delegates with multiple arguments

Canceling timers

Running a timer forever using vp_Timer.Start

vp_Timer.Handle

Creating timer handles

Canceling and blocking timers

Methods

Cancel

Execute

Properties

Debug Mode

Debug info

Created

Inactive

Active

Show Id

Show Callstack

反作弊(Cheat Detection)

Setup

ObscuredTypes Scripting Guide

When to implement ObscuredTypes?

Changing a variable in ANY SCRIPT into an ObscuredType

Changing a variable in a UFPS SCRIPT with a STATE MANAGER into an ObscuredType

Where to use ObscuredTypes?

Preventing obscured value reset in prefabs when updating UFPS

Additional scripting notes

'Unsupported type' editor error message

ObscuredTypes do not work with the ternary operator

There is no Vector4 ObscuredType

Sending an ObscuredType variable across the network in Photon PUN

支持和附加信息(Support and additional information)

Introduction

Congratulations on your purchase of UFPS! A whole new world of amazing FPS immersion is now at your fingertips. Many thousands of hours of work has gone into the design and programming of these systems and we hope you'll have tons of fun with them!

At the core of UFPS is an advanced procedural camera system, allowing you to manipulate the camera and weapon model for a vast range of complex, realtime-generated behaviors. Combining this with traditional animation can result in super-lifelike motion rivaling the best AAA games out there!

Imagine having an artillery shell detonate nearby, shaking your arms and the camera violently while you desperately attempt to reload a shotgun. Shell shocked, your vision, hands and movement pattern are disturbed for a while before returning to normal ...

In summary, the main emphasis of UFPS is immersive first person motion. That said, it is currently being expanded into a full FPS framework that will eventually cover every aspect of a first person game. It can already be used as a cornerstone for a new FPS. Great effort has also gone into keeping it modular, so you should be able to pick it apart and use bits and pieces of it in your existing systems.

Hope you'll have as fun working and playing with this system as we are having building it! Feel free to show off your game or participate in the official forum discussion at:

www.opsive.com/assets/UFPS/forum/

Also, stay up-to-date on current developments by following us on twitter:

https://twitter.com/Opsive

Good luck with your game!

Playing the demo

The walkthrough demo is fairly self-explanatory. Use the big arrows at the top of the screen to navigate back and forth between screens. Press the buttons to try out various settings.

Demo controls

WASD

Move

C

Crouch

Space

Jump

Shift

Sprint

R

Reload

Middle & Right Mouse Button

Aim Down Sights / Zoom

F

Use

G

Toggle GUI

ESC

Quit app (if offline standalone player)

Enter

Toggle menu

Getting started

Trying out the demo scenes

Sky City

This scene, made with ProBuilder, is an example of how UFPS can feel and behave in a real game environment. It's a sci-fi museum populated by dangerous security turrets programmed to annihilate any intruder (you). Collect the small arsenal of HD weapons near the initial spawnpoint and see if you can make it around the museum!

CleanScene

This scene  (located in the "Demo/Levels" folder) is a simple terrain with a basic first person camera and controller, intended for prototyping and experimentation.

DemoScene1

This scene (located in the "Demo/Levels" folder) is designed as a test range using a Half Life "orange map" style. Its content and FPS player is tightly integrated into a walkthrough of the most important features.

DemoScene2

This scene is as test range for physics testing. It has an extra "slidy" player and several ramps tilted at various degrees for different test cases. It also has examples of various types of moving platforms. To shut off the demo walkthrough, disable or delete the "Demo" gameobject in the scene Hierarchy. Upon pressing Play you can now run around freely.

DemoScene3

This scene is an outdoor environment with a base and a bunch of explosive cubes, breakable crates and pickups of various kinds. It is a demonstration of how to put some of the example gameplay scripts to use. To shut off the demo walkthrough, disable or delete the "Demo" gameobject in the scene Hierarchy. Upon pressing Play you will be able to explore freely with an advanced FPS player.

Using the example player prefabs in your own scene

  1. Make sure your scene has some kind of floor in it, for example a huge box with collision. An easy way of achieving this is going to the Unity main menu, choosing GameObject > Create Other > Cube and setting the position of the cube transform to (0, 0, 0) and its scale to (1000, 1, 1000).
  2. In the Project view, browse to the Content/Prefabs/Players folder (or type player in the search box) and drag one of the example player prefabs into your scene hierarchy. Make sure it is positioned slightly above the floor.

IMPORTANT: If you have a fresh scene with an auto-created Main Camera object in it, delete this object (or atleast its Audio Listener) or you will get Unity warnings in the console.


Important Concepts

If you are like us and skip through manuals, here's what you really need to know: UFPS is all about FP components, States and Events.

FP components

An FP script is a Unity component designed to be part of a local, First Person player. These all have names beginning with "vp_FP" and include the Player, the Controller, the Camera, its Weapons and their Shooters.

状态(States)

A State is a list of settings for a specific component during a specific activity. For example: the camera "Crouch" state has values in it defining a lower Y-position for the camera. The controller's "Crouch" state makes it slow down. States are saved in small scripts called 预设(Presets).

Events

Events are how FP components communicate. For example: when the character controller detects a ground impact from falling, it sends the force of impact to the Player Event Handler, which in turn broadcasts it to the camera and weapon components (making them shake).

TIP: If you are planning to do even just a little scripting with this system, it is a good idea to first have a glance at the 事件系统(Event system) chapter, and you will have more AHA! moments and fewer headaches.

Working in the editor

Adjusting values

Sliders are used to modify most variables. Text edit fields are used for variables with no limited range. Note that you can click and drag the text in front of a text edit field (for example the X) to adjust the value with the mouse.

Pressing and holding Alt while doing this gives you finer control. This is very useful when adjusting particular values, for example weapon position offset

Toggling between Game and Editor

Any time you want to toggle back and forth between the Inspector and the Game view without firing shots:

Navigating for text assets

The Unity Editor has a neat highlight feature which simplifies navigating for assets. To locate a text asset you see in a component State list, simply click on it and the text asset will be highlighted in the Project view. This gives you quick access to close by text presets compatible with the current component. You can also click directly on a text file in the Project view to inspect its values.

Another great way to quickly locate text assets is to write part of their names in the Project view search box).

Keep an eye on the Console

UFPS will communicate any detected errors and warnings via the Unity console. It's always a good idea to be aware of any red (Error) or yellow (Warning) messages it might display.

Most Unity crashes will result in an error message being shown in the console bar at the bottom left of the screen.

Click on the icon to open the full list of errors.

IMPORTANT: The displayed error may not be the one that caused your application to become unstable. To find the real source of a crash, you must often look further up the error list. The first and topmost (red) error message is often the culprit. Finding the name of the script and the line number of the crash in this way will often lead to AHA! moments.

Scripting

Beginner

To get started scripting with UFPS, check out the 基础脚本(Basic scripting) chapter. It will give you a very good overview of what the system can do in terms of manipulating the player object.

Intermediate

When you feel comfortable with the basics, it's a good idea to read up on the 事件系统(Event system) and 计时器 定时器(Timers) (both are central concepts to UFPS).

Code comments

Browsing through the scripts is also a great way of learning how the systems work. UFPS has very rich code commenting, and scripts will often contain additional useful info not found in the manual.

All methods in the included scripts use XML  <summary>  tags. Depending on your IDE (e.g. MonoDevelop / Visual Studio), this means you should be able to mouse-over on a method name in the code (or on a member name in a pop-up list) to display a brief description.

About the "vp_" filename prefix

The "vp_" prefix is a legacy from the original UFPS development team, VisionPunk. It will be removed in UFPS version 2.0, which is being developed by Opsive.

Creating an FPS Player from scratch

The demo scenes and prefabs will be sufficient for getting to know the system and playing around with its various parts. Once you're ready to dig a little deeper, these player creation tutorials will be good next steps for learning how things are set up.

Basic setup

  1. Create an empty gameobject and name it Player.
  2. Create a plane (or any kind of floor with collision) and place the player gameobject above it.
  3. Create another empty gameobject, name it Camera and drag it onto the first one so it becomes a child of the Player object.
  4. Set the position of the the new child gameobject to (0, 0, 0).
  5. In the project view search box, type vp_fp.
  6. Drag the vp_FPPlayerEventHandler script onto the Player gameobject.
  7. Drag the vp_FPController script onto the Player gameobject.
  8. Drag the vp_FPInput script also onto the Player gameobject.
  9. Drag the vp_FPCamera script onto the Camera gameobject.

TIP: Remember to clear the Project view search box when done.

  1. With the Camera gameobject selected, go to the top of the Inspector and set its Tag to MainCamera (if there was a default gameobject named "MainCamera" in the scene, delete it now).
  2. Press Play and you should now have a simple, working FPS controller and camera.

Adding a weapon

  1. If you haven't already, drag the vp_FPWeaponHandler script onto the Player gameobject.
  2. Create a new empty gameobject and give it the name of your weapon.
  3. Add a vp_FPWeapon component to your weapon gameobject.
  4. Open the weapon component's Rendering foldout, and drag a weapon prefab into the Weapon Prefab slot.

  1. Drag the weapon gameobject onto the Camera object so that it becomes a child of the camera.
  2. Set the weapon transform's position to (0, 0, 0).
  3. Press Play, then the 1 or E button, try moving and jumping, and there should now be a swaying weapon model in the view. If you don't see the weapon right away, proceed with the next section, Adjusting weapon position.
  4. To add more weapons, simply repeat steps 1-6 above.

TIP: If you have more than one weapon, it's a good idea to prefix the name of your weapon object with a number. This will not only define weapon order in the hierarchy. It will also control the order of the weapons when toggled.

A weapon prefab means a prefab containing a mesh filter, a mesh renderer and materials. For more info about prefabs and how to set them up, see these articles:

   
http://docs.unity3d.com/Documentation/Manual/Prefabs.html
   
http://docs.unity3d.com/Documentation/Components/comp-MeshGroup.html
   
http://docs.unity3d.com/Documentation/Manual/Materials.html

Adjusting weapon position

  1. Start the game.
  2. Open the weapon's Position Springs foldout and gently increase Offset:Z until you see the weapon. Also adjust X and Y to your liking.
  3. For weapon angle, do the same under the Rotation Springs foldout.

  1. When happy with your weapon's default position and orientation, go to the Preset foldout at the bottom of the weapon component and click the Save button (make sure to do this in the Preset section of the weapon component and not another component).
  2. Stop the game and Load your weapon preset script onto the component.


Adding a weapon camera

Using a weapon camera will prevent the weapon from intersecting other objects in the scene, and will give you greater control over weapon appearance. Though this is optional, in most cases you will want one.

  1. Create a new empty gameobject, name it WeaponCamera and drag it onto the FPSCamera gameobject (setting it up as a child of the camera gameobject).

  1. Set the position of the WeaponCamera gameobject to (0, 0, 0).
  2. Select the WeaponCamera gameobject, go to the Unity main menu and choose Component > Rendering > Camera. Your weapon camera gameobject should now have a basic Camera component on it in the Inspector.

IMPORTANT: You should only create one weapon camera (not one per weapon).

Adding a projectile

  1. Drag the vp_FPWeaponShooter script onto your weapon gameobject.
  2. In the Inspector, expand the 声音(Sound) foldout on the FPWeaponShooter component. In the Project view search box, type pistolfire and drag the pistol sound to the 火焰(Fire) slot in the Inspector.
  3. Expand the shooter's Projectile foldout. In the Project view search box, type pistolbullet and drag the PistolBullet prefab to the Projectile > Prefab slot in the Inspector.
  4. If you start the game now and press the left mouse button, the weapon should shoot bullets, play a fire sound and shake with a spring motion. The recoil doesn't yet look very realistic though! See the next section for info on how to make it look better.

Adjusting the recoil

  1. Start the game.
  2. Go to the vp_FPWeapon component in the Hierarchy and open its Position Springs foldout.
  3. Find the Spring2 Stiffness/Damping sliders and type the following into the respective field:

        弹簧2硬度(Spring2 Stiffness): 0.2
           弹簧2阻尼(Spring2 Damping):
    0.55 

  1. Similarly, open the 弹簧旋转 or 弹性旋转(Rotation Springs) foldout, find the Spring2 Stiffness/Damping sliders there and set them to:

            弹簧2硬度(Spring2 Stiffness): 0.85
           弹簧2阻尼(Spring2 Damping):
    0.6
  2. Now fire the weapon in the game view to see the result. Of course, these values are only examples. Keep adjusting until you think it looks good.
  1. When happy with your modifications, with the game still running, go to the Preset foldout at the bottom of the weapon component (Note: not the shooter component) and click the Save button.
  2. Stop the game and Load your new weapon preset onto the component.

That's about it! There are obviously many more powerful features and things to learn about the various components. Play around and browse this manual for information and ideas.

Animation concepts

One of the really unique and cool things about UFPS is how it makes heavy use of procedural motion for animating the camera and weapons. This means it is not dependent on "regular" animations. Instead, most motion is generated in realtime depending on player input, movement, and external physics forces, which makes everything a lot more organic and natural. You are one with the camera and weapons.

Another huge benefit of procedural motion is that you don't have to animate every weapon individually. You don't even have to know a single thing about animating models! As long as there is a static 3d model, UFPS will animate it for you in realtime. Once you have motions for one weapon type - for example a pistol - the motions work instantly on all pistols with minor tweaks.

Here's the thing: using procedural motion in conjunction with traditional animation can result in incredibly realistic and lifelike motion, strongly promoting suspension of disbelief and giving your game a special edge.

Springs

   

The main workhorse of UFPS is a spring system that operates on transform position, rotation or scale. The spring has a Rest State (also known as the "static equilibrium") where it "wants to be". If you move it away from the target value using external force, it will immediately and continuously strive back to its target position or angle. The spring Stiffness - or mechanical strength - determines how loosely or rigidly the spring behaves. Finally, the Damping makes spring velocity wear off as it approaches its rest state. Springs can be used to simulate everything from jello (a loose spring operating on object scale), an arrow hitting a wall (a very stiff spring rotating the arrow with the pivot at the head) or an underwater camera (a loose spring making the camera bounce softly as your feet hit the ocean floor).

上下摆动(Bob)

Bob is the sinusoidal motion of an object or the camera. View bob has been around in first person shooters for ages as a means of moving the camera up and down when walking. Modern shooters don't always have a very pronounced view bob, but bob is still very useful for animating the weapon model (and camera if used in moderation). If applying bob along both the x and y vector you can get interesting results such as the feeling of being a dinosaur or a huge ogre.

Noise

     

Procedural noise has been used in computer graphics and special effects for years as a means of generating smoke, terrains and camera shakes (to name but a few areas). UFPS uses a standard perlin noise function for applying random turbulence to the weapon and camera. For example: a slight breathing camera motion as you zoom in with a sniper rifle, gentle idle movements for a hand holding a sub machine gun, or the heavily disturbed camera movements of a character that is drunk or poisoned.

Animations

Since UFPS' procedural motion systems only operate on a model's pivot and transform, they won't handle more complex animations. For example, if you want to do things "inside" the weapon model - such as bending an arm or fingers -  you have to use a model with animations (this is also true for pistol / rifle reload animations).

That said, UFPS provides plenty of hooks for playing such weapon animations, e.g. when wielding, unwielding, firing and reloading weapons. The weapon class even has a cool ambient animation scheduler which will play a random idle animation from a list provided by you at random intervals. For more info about this, see the 动画(Animation) section of the Weapons chapter.

计时器 定时器(Timers)

UFPS makes massive use of our own timer logic, vp_Timer. This is a very powerful and easy-to-use script extension for delaying (scheduling) methods (such as animations or physics force impacts) with a time delay. The system has many commands an options and is well worth checking out for all sorts of sequential animation and gameplay programming tasks.

The pistol reload animation in the demo was actually made using procedural animations only. It was an experiment to see how far we could push the motion systems using only springs and timers. For more info, study the comments in the vp_PistolReloader script.

The Controller

vp_FPController is an extended character controller designed to work perfectly with the vp_FPCamera class. It features acceleration, sliding, air control, wall bouncing, external forces and the ability to push around rigidbodies.

The controller doesn't rotate by itself. To rotate it via mouselook, add an FPCamera to its hierarchy as described in the Creating an FPS Player from scratch chapter.

Motor

The Motor foldout contains all basic movement parameters of the FPController.

Acceleration

The amount of world velocity added to the controller every frame when moving.

Damping

How quickly velocity should deteriorate when movement stops. Low values will get you a "slippery floor" or icy feeling. High values will slow down the controller.

TIP: If you're not a big fan of "slidy" controls, set both Acceleration and Damping to 1 and reduce damping until you're happy with the walking speed. This will get you a controller that stops abruptly.

TIP: If you want to tweak the controller for a specific real world max speed, you may output the player's speed in meters per second using this line of code:

Debug.Log(Controller.Velocity.magnitude);

Air Speed

A factor determining how fast the controller can move when it has no contract with the ground (jumping, falling or flying). A value of 0 means the player can not move sideways at all when flying (like a real world human). A value of 1 means the player can move as quickly in the air as on the ground. This is often used in games to increase the feeling of control, especially if platform jumping is a gameplay element.

Slope Speed Up

This value increases or decreases controller velocity on upward slopes. At 1.0, velocity on upward slopes will be kept roughly the same as on flat ground. Values lower or higher than 1 will make the controller slow down / speed up on upward slopes, respectively.

TIP: The slope speed feature can be especially useful on outdoor terrain; try setting "Slope Speed Up" to 0.5 and "Slope Speed Down" to 1.5. This will slow down the controller moving uphill, and give it a speed boost running downhill.

Slope Speed Down

This value increases or decreases controller velocity on downward slopes. At 1.0, velocity on downward slopes will be kept roughly the same as on flat ground. Values lower or higher than 1 will make the controller slow down / speed up on downward slopes, respectively.

Free Fly

When active, this enables a throttle logic for moving a flying controller in an arbitrary direction based on player (camera) forward vector. This can be used for many things in an FPS, for example spectator cams, ingame editor modes, zero gravity, swimming underwater, jetpacks and superhero style flying. Free fly movement can be toggled at any time. This feature works best if the Physics > Gravity Modifier is zero or very low.

Jumping and crouching behaves differently in Free Fly mode. The Jump activity will make the camera go straight up. The Crouch activity will make it go straight down. The collider will only shrink upon crouching if the controller has ground contact.

Jump

The Jump foldout contains parameters allowing you to design a highly customized jumping behaviour for your player.

Force

The amount of up-force that is added to the character controller in a single frame when the player jumps. The height of the jump is slightly influenced by the gravity modifier.

Force Damping

This parameter determines how quickly the jump force wears off.

Force (Hold)

The amount of force to add per frame if the jump button is being held down continuously. This is a common feature for providing increased jump control in platform games. A large value here will have sort of a jetpack effect. To remove this feature, just set it to zero.

Force Damping (Hold)

Determines how quickly the hold jump force wears off.

Physics

The Physics foldout contains parameters governing how various laws of nature should affect the controller.


Force Damping

This value scales how receptive the controller is to scripted external forces such as explosion knockback. A value of 1 means it is not affected at all, like an extremely heavy object. A value of 0 means the controller will be affected enormously, as would a very light object.

Push Force

This value determines how "strong" the controller is when pushing around physical objects (rigidbodies). Rigidbodies with larger mass will be harder to move.

Gravity Modifier

The gravity modifier regulates how much the controller will be affected by gravity. Higher values give a heavier feel. The "Physics.Gravity" value of the Unity Physics Manager affects the object aswell.

Slope Slide Limit

The ground steepness in angles above which controller will start to slide.

Slope Slidiness

Slidiness of the surface that we're standing on. Will be additive if steeper than the (regular Unity) CharacterController's "slopeLimit" parameter.

TIP: You can alter PhysicsSlopeSlidiness and SlopeSlideLimit in realtime using the state manager depending on the current ground surface, for example by enabling a special sliding state on the vp_FPController via a trigger.

Wall Bounce

This feature makes the character controller bounce when moved by external forces such as explosions , giving a slightly more organic feel on wall collision (note that it does not apply to regular player movement).

Wall Friction

This feature determines how much the character controller should slide against surfaces when moved by external forces such as explosions (note that it does not apply to regular player movement).

Has collision trigger

The collision trigger is a scripting feature used for interacting with rigidbody objects such as 运动平台(Moving Platforms). When this is active (default) a child gameobject is generated on startup, with an encompassing capsule collider trigger. This is to allow physics responses to incoming rigidbodies.

IMPORTANT: Without a trigger, the controller will still be able to ride on moving platforms, but the platforms will not auto-start when stood upon and will not be able to push the player around or use its intersection solver.

The collision trigger may sometimes affect raycast or trigger logic. If you are experiencing issues with raycasts not hitting the player, make sure the raycast hits the actual charactercontroller, or send a message from the trigger to the controller using "SendMessageUpwards". See how this works in the vp_HitscanBullet script.

The Camera

The vp_FPCamera class governs all behaviour of the first person camera which is a child to the main player gameobject. It features mouse smoothing, view bob, camera shakes, smooth zooming, kneeling and reacting to external forces among many other things.

Mouse


Sensitivity

Sets mouse sensitivity in the X (yaw) and Y (pitch) axes.

Smooth Steps

Mouse smoothing interpolates mouse input over several frames to reduce jerky player input. "Smooth Steps" determines how many of the most recent frames of mouse input to average. A typical value is 10.

Smooth Weight

"Smooth Weight" determines the influence of recent mouse input as it ages. Reducing the weight modifier to 0 will provide the user with raw, unfiltered feedback. Increasing it to 1.0 will cause the result to be a simple average of all the recently sampled smooth steps (and will feel very laggy). A typical value is 0.5.

Acceleration

Mouse acceleration increases the mouse sensitivity above certain speeds. Along with low mouse sensitivity this allows high precision without loss of turn speed. It gives you optimal precision at slow mouse movements (for example when sniping), but will also allow you to turn 180 degrees quickly to aim at someone behind you.

Acceleration Threshold

Describes the speed above which mouse acceleration will be activated. If you move your hand above this set speed, mouse acceleration will kick in.

Rendering


Field of View

Sets the target FOV of the first person camera.

Zoom Damping

Determines how fast the camera will interpolate to the target value when FOV is changed from script. Higher values result in slower zoom.

Disable VR mode on startup

This setting will temporarily disable the setting 'Virtual Reality Supported' (found under Project Settings) when the vp_FPCamera wakes up, and re-enable it when needed. This may seem counter-intuitive for a VR game, but is an important workflow feature. For more info, see this section in the VR chapter.

Position Spring

The camera position is hooked to two springs, allowing for a host of interesting effects. The first, "regular" spring is used for reacting to player movements that need a soft spring setting. The second spring is intended for external forces that require stronger spring settings, such as the camera shaking violently from an artillery impact.


偏移量(Offset)

Camera position offset relative to the player. For example: to create a crouch animation, you can smoothly lower the camera with the Y-offset. To peek around corners without moving the character, you can move the camera sideways using x-offset.

This position is where the camera "wants to be". If you move it away from the target value using external force, it will immediately try to go back to the target position.

Ground Limit

A vertical limit intended to prevent the camera from intersecting the ground. The value is in negative world units relative to the camera position. It determines how far below the normal head position the camera is allowed to go when kneeling or reacting to external forces or camera bob.

弹簧硬度(Spring Stiffness)

Camera spring stiffness - or mechanical strength - determines how loosely or rigidly the camera spring behaves. A low value will result in a soft, swaying motion, and higher values will result in stronger spring movements.

弹簧阻尼(Spring Damping)

Camera spring damping makes spring velocity wear off as it approaches its rest state. Low values will result in a very loose, swaying motion, while higher values can result in either motion that quickly grinds to a halt, or a stiff shaking motion (much depending on the spring stiffness setting).

弹簧2硬度(Spring2 Stiffness)

Stiffness for the secondary camera spring. This spring is intended for external forces. It does not automatically do anything. Instead, activate it using the "AddForce2" script function of vp_FPCamera. See the DemoScript for example usage.

弹簧2阻尼(Spring2 Damping)

Damping for the secondary camera spring. This spring is intended for external forces. It does not automatically do anything. Instead, activate it using the "AddForce2" script function of vp_FPCamera. See the DemoScript for example usage.

跌落时重心下降(Kneeling)

Determines how much the camera will be pushed down when the player falls onto a surface.

跌落时重心下降柔性参数(Kneeling Softness)

The number of frames over which to even out each fall impact for kneeling. A higher number will slow down the kneeling. A lower number will be more 'snappy'.

地震参数(Earthquake Factor)

Exaggerates or reduces the down force imposed on this camera by earthquakes.

Rotation

The camera is mainly rotated by mouse input and camera shakes. It also has a rotation spring, mostly used for rotating around the Z vector (rolling) by means of external forces.


Pitch Limit

Limits vertical mouse rotation of  the camera.

Yaw Limit

Limits horizontal mouse rotation of  the camera. Useful mainly for creating things like gun turrets. It could also be useful for players mounted on vehicles, let's say a player shooting out of a car side window.

跌落时重心下降(Kneeling)

Determines how much the camera will be rotated when the player falls onto a surface. There is a 50% chance the camera will rotate left versus right upon impact.

跌落时重心下降柔性参数(Kneeling Softness)

The number of frames over which to even out each fall impact for kneeling. A higher number will slow down the kneeling. A lower number will be more 'snappy'.

Strafe Roll

This variable rotates the camera depending on sideways local velocity of the character controller, resulting in the camera leaning into or away from its sideways movement direction. It's useful when moving and crouching. Larger positive values (2.0 and above) will result in a motorcycle or airplane type behaviour.

地震参数(Earthquake Factor)

Exaggerates or reduces the rotation force imposed on this camera by earthquakes.


震动(Shake)

UFPS uses a standard perlin noise function for applying random turbulence to the weapon and camera. For example: a slight breathing camera motion as you zoom in with a sniper rifle, gentle idle movements for a hand holding a sub machine gun, or the heavily disturbed camera movements of a character that is drunk or poisoned.


速度(Speed)

Determines the shaking speed of the camera.

振幅 幅度(Amplitude)

The strength of the angular camera shake around the X, Y and Z vectors. X and Y shakes are applied to the actual controls of the character model while Z is only applied to the camera. If you increase the shakes, you will essentially get a drunken / sick / drugged movement experience. This can also be used for i.e. sniper breathing since it will affect aiming.

上下摆动(Bob)

View bob is the sinusoidal relative motion of the camera, hooked to character controller velocity. If applying bob along both the x and y vector you can get interesting results such as the feeling of being a dinosaur or a huge ogre.


等级 比率(Rate)

Speed of the camera bob. X, Y and Z is positional motion. W is roll around the forward vector (tilting the head from left to right). A typical value for Y is 0.9.

振幅 幅度(Amplitude)

The strength of the camera bob. Determines how far the camera swings in each respective direction. For camera bob, X, Y and Z is positional motion. W is roll around the forward vector (tilting the head from left to right). A typical value for Y is 0.1.

Step Threshold

A feature for syncing bob motion with a script callback. The bob step callback is triggered when the vertical camera bob reaches its bottom value (provided that the speed is higher than the bob step threshold). This can be used for footstep sounds and various other behaviours.

This feature is not automatically used by the camera (although external components such as the vp_PlayerFootFXHandler will hook into it). If you want to use it for additional purposes, you need to provide a callback through script. Here is an example of how to set up a bob step callback:

Camera.BobStepCallback += delegate()

{

        Camera.AddForce2(new Vector3(0.0f, -1.0f, 0.0f));

};

This snippet will apply a sharp stomping motion on the camera for every footstep. It will be called once whenever the camera reaches its lowest bob point and changes direction

输入速度刻度(Input Velocity Scale 目前难以理解)

This tweaking feature is useful if the bob motion goes out of hand after changing player velocity. Just use this slider to scale back the bob without having to adjust lots of values.

最大输入速度(Max Input Velocity 目前难以理解)

A cap on the velocity value being fed into the bob function, preventing the camera from flipping out when the character travels at excessive speeds (such as when affected by a jump pad or a speed boost).

TIP: The current speed used by the camera bob can be displayed in script using:

Debug.Log(FPController.Velocity.sqrMagnitude);

Require ground contact

This determines whether bob should stay in effect when jumping, falling or flying. Disabling this is useful for doing flying dinosaurs, underwater movement et cetera.

Weapons

In UFPS, 1st person weapons are implemented by adding empty child gameobjects to the FPCamera transform and dragging vp_FPWeapon components onto each gameobject.

When the game starts, any such gameobjects are put in a list and may be toggled on or off from script. The weapons are arranged in alphabetical order, so you have great control over the order of your weapons, e.g. by putting numbers at the beginning of their names in the Hierarchy.

The runtime responsibility of the vp_FPWeapon component is to animate a weapon using its procedural motion properties. This means the component will manipulate the weapon transform's position and rotation using springs, bob and perlin noise. For more info about this, see the Animation Concepts chapter.

Note that the vp_FPWeapon class is not responsible for shooting logic, only for motion resulting from player movement or external forces. This is because an FPWeapon is not necessarily a firearm. It could just as easily be a knife, an axe, a crowbar or a couple of fists. All firearm specific features exist in a separate class called vp_FPWeaponShooter.

In UFPS, weapon availability is not controlled by adding or removing weapon gameobjects to the FPCamera hierarchy dynamically. Instead, the camera hierarchy is meant to parent all the weapons the player will ever be able to carry. The game code simply allows or prevent the player from activating these depending on the inventory state. By default, this is handled by the vp_WeaponHandler and the vp_PlayerInventory scripts.

Positioning a model in your 3d art package

The weapon should be rotated straight forward with no rotation around the X or Y axis (otherwise the iron sights won't match up by default when zooming). You can set the ingame position and rotation (aswell as the pivot) in the Inspector and in the preset scripts, so that doesn't really matter, but in general we recommend to keep the weapon 100% centered in the X axis, roughly centered in the Y axis and to keep the elbow of the arm at about the center of the Z axis. This way you'll make sure the weapon will be visible by default when added to the FPSPlayer, simplifying further editing. If you will be making many weapons, this rough placement is a good standard to conform to. Final tweaking of position and rotation should be done in the Position Springs and 弹簧旋转 or 弹性旋转(Rotation Springs) foldouts of the vp_FPWeapon component.

Avoiding camera clipping

One important thing to remember when you create (or choose) a model is that any arm geometry should be positioned so an imaginary tube (about 3 inches in diameter) would be able to pass from the top of the wrist to the camera plane without touching any arm geometry. If it does, you will have trouble with the camera clipping arms ingame at some point (we call this the Pringles Tube Rule).

The "Pringles Tube Rule"

Choosing a world intersection solution

A common problem in FPS construction is preventing weapons from sticking through walls and other geometry. UFPS allows you to choose between two very different solutions to this issue.

1. Weapon Camera

This is the classic approach, where weapons are rendered by a second camera, after the scene has been rendered. This gives you greater control over weapon appearance, since you may change the Field of View (FOV) of the weapon camera independently of the vp_FPCamera. However, it comes with a couple of drawbacks:

For more info about the Weapon Camera and gameobject and component setup, see the Adding a weapon camera tutorial.

2. 回缩(Retraction)

This feature approaches the intersection problem in a more "realistic" manner. It allows you to run the system without a weapon camera. Instead, every frame a raycast is made from the weapon into the environment. Whenever the raycast hits something, the weapon is pulled back accordingly. Using this approach your weapon will feel more like a part of  the world geometrically. Shadows from world objects will be cast on the weapon model, which looks very nice. However, drawbacks include:

TIP: Although the Retraction feature is intended for running the system without a weapon camera, nothing prevents you from using the systems together. In fact, Retraction can be a small extra nice touch to "weapon camera weapons".

Rendering

The vp_FPWeapon's Rendering foldout manages what to render for the weapon and how to render it.

Weapon Prefab

This slot should contain the model to be rendered for this weapon. A weapon prefab means a prefab containing a mesh filter, a mesh renderer and materials. For more info about prefabs and how to set them up, see these articles:

   
http://docs.unity3d.com/Documentation/Manual/Prefabs.html
   
http://docs.unity3d.com/Documentation/Components/comp-MeshGroup.html
   
http://docs.unity3d.com/Documentation/Manual/Materials.html

Field of View

This slider sets the Field of View for the weapon camera (if using one). It gives you great control over the appearance of the weapon. Tweak this along with weapon position and rotation offset to get the exact placement and perspective that you want.

Zoom Damping

Determines how fast the weapon will interpolate to the target value when FOV is changed from script. Higher values result in slower zoom.

Clipping Planes

Determines the near and far clipping planes of the weapon camera. Very useful in situations where you want to use a specific FOV and positional / rotational offset for the weapon, but parts of the weapon mesh intersect the view too close to the camera. In these cases, simply increase the near clipping plane. This is best done at runtime by clicking and dragging on "Clipping plane: X" in the Inspector while holding the "Alt" key.

Z Scale

Z Scale is intended for tweaking the appearance of the weapon when running the system without a weapon camera. See the 回缩(Retraction) section for a use case.

Position Springs

The weapon is hooked to its own position and rotation springs. Just like the camera it supports bob, shakes and external forces. It applies player local velocity to its position when walking and falling. The weapon has special position and rotation springs for additional forces such as recoil. The pivot point of the weapon is also hooked to a spring, and manipulating this at runtime can be quite useful.



偏移量(Offset)

Weapon position offset relative to the weapon object position. This position is where the weapon "wants to be". If you move it away from the target value using external force, it will immediately try to go back to the target position.

Exit Offset

This position is used by the parent FPCamera for switching weapons. It will move the current weapon model to its Exit Offset, switch weapons and move the new weapon into view, starting at its Exit Offset.

轴点 or 参照点 or 中心点(Pivot)

This setting manipulates the pivot point of the weapon model. A value of "0, 0, 0" will leave the object's pivot at the point defined in the 3d object file.

The relation between pivot and weapon model position is affected by rotations. This may lead to unexpected behaviour when moving the pivot in the editor. Before editing weapon pivot it is best to turn off weapon shake and set weapon rotation offset to (0, 0, 0).

轴点 or 参照点 or 中心点的硬度(Pivot Stiffness)

Pivot spring stiffness - or mechanical strength - determines how loosely or rigidly the pivot spring behaves. A low value will result in a soft, swaying motion, and higher values will result in stronger spring movements.

In some scripting situations you may need to move the weapon offset and pivot offset at the same time. In these cases you may want to make sure that the two springs share the same Stiffness and Damping settings, and are moved approximately the same distance, or one spring will finish before the other. On the other hand, this results in a more complex animation and may sometimes be desireable. If you run into problems related to pivot switching in script, try calling the "SnapPivot" method of vp_FPWeapon.cs.

轴点 or 参照点 or 中心点的阻尼(Pivot Damping)

Pivot spring damping makes spring velocity wear off as it approaches its rest state. Low values will result in a very loose, swaying motion, while higher values can result in either motion that quickly grinds to a halt, or a stiff shaking motion (much depending on the pivot stiffness setting).

Show Pivot

Toggles pivot point visualization on or off for editing purposes. The pivot point looks like a blue transparent ball. It can only be visualized when the game is playing.

TIP: Set Pivot Z to about -0.5 to bring it into view.

弹簧硬度(Spring Stiffness)

Weapon spring stiffness - or mechanical strength - determines how loosely or rigidly the weapon spring behaves. A low value will result in a soft, swaying motion, and higher values will result in stronger spring movements.

弹簧阻尼(Spring Damping)

Weapon spring damping makes spring velocity wear off as it approaches its rest state. Low values will result in a very loose, swaying motion, while higher values can result in either motion that quickly grinds to a halt, or a stiff shaking motion (much depending on the weapon stiffness setting).

弹簧2硬度(Spring2 Stiffness)

Positional stiffness for the second weapon spring. This spring is intended for additional forces such as recoil. It is not used internally by vp_FPWeapon, but the vp_FPWeaponShooter component uses it for recoil. It can also be activated using the "AddForce2" script function of vp_FPWeapon.

弹簧2阻尼(Spring2 Damping)

Positional damping for the second weapon spring. This spring is intended for additional forces such as recoil. It is not used internally by vp_FPWeapon, but the vp_FPWeaponShooter component triggers it for recoil. It can also be activated using the "AddForce2" script function of vp_FPWeapon.

跌落时重心下降(Kneeling)

Determines how much the weapon will be pushed down when the player falls onto a surface.

跌落时重心下降柔性参数(Kneeling Softness)

The number of frames over which to even out each fall impact.

跌落回缩(Fall Retract)

Makes the weapon pull backward while falling.

行走滑动(Walk Sliding)

Walk sliding moves the weapon in different directions depending on character controller movement direction.

输入速度刻度(Input Velocity Scale 目前难以理解)

This tweak feature is useful if the spring motion goes out of hand after changing player velocity. Just use this slider to scale back the spring motion without having to adjust lots of values.

最大输入速度(Max Input Velocity 目前难以理解)

A cap on the velocity value being fed into the weapon swaying method, preventing the weapon from flipping out when the character travels at excessive speeds (such as when affected by a jump pad or a speed boost). This also affects fall sway.

TIP: The current speed used by weapon swaying can be displayed in script using:

Debug.Log(Controller.Velocity.magnitude);

弹簧旋转 or 弹性旋转(Rotation Springs)

Weapon rotation is affected via springs by mouse movements and character controller motion. It can also be affected by external forces such as falling impact, and additional forces such as recoil.


偏移量(Offset)

Weapon rotation offset. This angle is where the weapon "wants to be". If you turn it away from the target value using external force, it will immediately try to swing back to the target angle.

Exit Offset

This angle is used by the parent FPCamera for switching weapons. It will move the current weapon model to its Exit Offset, switch weapons and move the new weapon into view, starting at its Exit Offset.

轴点 or 参照点 or 中心点(Pivot)

This setting manipulates the angle of the weapon model's pivot point at runtime. A value of "0, 0, 0" will use the value defined in the 3d object file.

TIP: The relation between pivot and weapon model position is affected by rotations. This may lead to unexpected behaviour when moving the pivot in the editor. Before editing weapon pivot it is best to turn off weapon shake and set weapon rotation offset to (0, 0, 0).

轴点 or 参照点 or 中心点的硬度(Pivot Stiffness)

Pivot spring stiffness - or mechanical strength - determines how loosely or rigidly the pivot spring behaves. A low value will result in a soft, swaying motion, and higher values will result in stronger spring movements.

In some scripting situations you may need to move the rotation spring and pivot spring at the same time. In these cases you may want to make sure that the two springs share the same Stiffness and Damping settings, and are moved approximately the same distance, or one spring will finish before the other. On the other hand, this results in a more complex animation and may sometimes be desireable. If you run into problems related to pivot switching in script, try calling the "SnapPivot" method of vp_FPWeapon.cs.

轴点 or 参照点 or 中心点的阻尼(Pivot Damping)

Pivot spring damping makes spring velocity wear off as it approaches its rest state. Low values will result in a very loose, swaying motion, while higher values can result in either motion that quickly grinds to a halt, or a stiff shaking motion (much depending on the pivot stiffness setting).


Show Pivot

Toggles pivot point visualization on or off for editing purposes. The pivot point looks like a blue transparent ball. It can only be visualized when the game is playing.

TIP: Set Pivot Z position to about -0.5 to bring it into view.

弹簧硬度(Spring Stiffness)

Weapon rotation spring stiffness determines how loosely or rigidly the weapon rotation spring behaves. A low value will result in a soft, swaying motion, and higher values will result in stronger spring movements.

弹簧阻尼(Spring Damping)

Weapon rotation spring damping makes spring velocity wear off as it approaches its rest state. Low values will result in a very loose, swaying motion, while higher values can result in either motion that quickly grinds to a halt, or a stiff shaking motion (much depending on the weapon stiffness setting).

弹簧2硬度(Spring2 Stiffness)

Angular stiffness for the second weapon spring. This spring is intended for additional forces such as recoil. It is not used internally by vp_FPWeapon, but the vp_FPWeaponShooter component uses it for recoil. It can also be activated using the "AddForce2" script function of vp_FPWeapon.

弹簧2阻尼(Spring2 Damping)

Angular damping for the second weapon spring. This spring is intended for additional forces such as recoil. It is not used internally by vp_FPWeapon, but the vp_FPWeaponShooter component uses it for recoil. It can also be activated using the "AddForce2" script function of vp_FPWeapon.

跌落时重心下降(Kneeling)

Kneeling determines the amount of downward pitch force the weapon will receive upon fall impact.

跌落时重心下降柔性参数(Kneeling Softness)

The number of frames over which to even out angular force resulting from a fall impact.

Look Sway

This setting determines how much the weapon sways (rotates) in reaction to mouse movements. Horizontal and vertical mouse movements will sway the weapon spring around the Y and X vectors, respectively. Rotation around the Z vector is hooked to horizontal mouse movement, which is very useful for swaying long melee weapons such as swords or clubs.

Strafe Sway

Rotation strafe sway rotates the weapon in different directions depending on character controller movement direction.

Fall Sway

This setting rotates the weapon in response to vertical motion (e.g. falling or walking in stairs). Rotations will have opposing direction when falling versus rising. However, the weapon will only rotate around the Z axis while moving downwards / falling.

Slope Sway

This parameter reduces the effect of weapon Fall Sway when moving on the ground. At a value of 1.0, the weapon behaves as if the player was falling. A value of 0.0 will disable Fall Sway altogether when the controller is grounded.

Input Rotation Scale

A tweak feature that can be used to temporarily alter the impact of mouse input motion on the weapon rotation spring, for example in a special player state.

Max Input Rotation

A cap on the mouse input motion being fed into the weapon swaying method, preventing the weapon from flipping out when extreme mouse sensitivities are being used.

回缩(Retraction)

The 回缩(Retraction) feature is intended for running the system without a weapon camera. Basically, this feature will pull back weapons when too close to walls. It makes for more realistic weapon rendering, but can also be a little trickier to use.

回缩指南(Retraction tutorial)

The first thing you will notice when removing the weapon camera is that all the default presets are currently adapted to weapon camera use (for starters the weapon will probably sit way too far away), so you will want to retweak some weapon settings. Here is a quick rundown:

  1. In the "Position Springs" foldout, modify "Offset:Z" until the weapon sits in its proper place along the Z-axis.
  2. Optionally, go into the weapon's "Rendering" foldout and reduce "Z scale" slightly until the weapon doesn't have a strecthed out / distorted perspective.
  3. Start the game and walk up to a wall so the weapon sticks through it while you are looking down at a ~45 degree angle.
  4. Go into the weapon's "Retraction" foldout and gently increase "Distance" until the weapon no longer intersects the wall.

  1. You will likely need to tweak recoil and other settings so they look better without the weapon camera.

If you manage to tweak all these things nicely, it will sometimes look even better without the weapon camera! For more info on pros and cons of the two options, see the Choosing a world intersection solution chapter.

距离(Distance)

The length of the raycast used for performing retraction. The weapon will be pulled back a distance corresponding to the length of the overlap. A typical value is 0.5.

偏移量(Offset)

This parameter will offset the retraction raycast horizontally and / or vertically in relation to the weapon. While the 回缩(Retraction) foldout is open, a debug ray will be drawn in the Scene view. The ray will be yellow if it doesn't intersect anything, and red if it does. For the best result, tweak the 偏移量(Offset) parameter until it runs inside the weapon's barrel (if any).

位置返回常规状态速度(Relax Speed)

This slider can be used to adjust how quickly the weapon will ease back into its regular Z position after an intersection has ended.

震动(Shake)

This is procedural weapon rotation shaking, intended as a purely aesthetic motion to breathe life into the weapon. Super-useful for idle motions, but can also be used to rattle the weapon from wind turbulence when skydiving!


速度(Speed)

Determines the shaking speed of the weapon.

振幅 幅度(Amplitude)

The strength of the angular weapon shake around the X, Y and Z vectors.

上下摆动(Bob)

Weapon bob is the sinusoidal motion of the weapon, hooked to character controller velocity.


等级 比率(Rate)

Speed of the weapon bob. X & Z rate should be (Y/2) for a classic weapon bob. To invert the curve, make X and Y negative. For weapon bob, X, Y and Z is angular bob. W is the position along the forward vector (pushing back and forth). A typical value for Y is 0.9.

振幅 幅度(Amplitude)

The strength of the weapon bob. Determines how far the weapon swings in each respective direction. For weapon bob, X, Y and Z is positional motion. W is roll around the forward vector (tilting the head from left to right). A typical value for Y is 0.1.

输入速度刻度(Input Velocity Scale 目前难以理解)

This tweak feature is useful if the bob motion goes out of hand after changing player velocity. Just use this slider to scale back the effect without having to adjust lots of values.

最大输入速度(Max Input Velocity 目前难以理解)

A cap on the velocity value being fed into the bob function, preventing the weapon from flipping out when the character travels at excessive speeds (such as when affected by a jump pad or a speed boost).

TIP: The current player velocity can be displayed in script using:

Debug.Log(Controller.Velocity.magnitude);

Require ground contact

This determines whether bob should stay in effect when jumping, falling or flying. Disabling this is useful for doing flying dinosaurs, underwater movement et cetera.

Step

The Step feature applies force to the weapon springs in order to simulate a fine footstep impact in sync with the weapon bob. A footstep force is triggered every time the vertical weapon bob reaches its bottom value.

TIP: Try exagerrating weapon Y bob while also using steps.

This feature was developed to achieve procedural weapon motions rivaling the very best FPS games out there. If used in concert with regular weapon bob (and with decent understanding of position, rotation and pivot springs) it is indeed possible to achieve very realistic looking footstep motions.

Min Velocity

This parameter sets the minimum squared controller velocity at which footstep impacts will occur on the weapon. The system will be disabled if is zero (default).

TIP: To measure the controller's squared velocity you can do this in script:

Debug.Log(m_Controller.Velocity.sqrMagnitude);

Step Softness

The number of frames over which to even out each footstep impact. A higher number will make the footstep softer (more like regular bob). A lower number will be more 'snappy'.

Position Force

A vector relative to the weapon, determining the amount of force it will receive upon each footstep. Note that this parameter is very sensitive. A typical value is lower than 0.01.

Rotation Force

Determines the amount of angular force the weapon will receive upon each footstep. Note that this parameter is very sensitive. A typical value is lower than 0.01.

Force Scale

This value scales the impact force. It can be used for tweaking the overall force when you are satisfied with the axes' internal relations.

Position Balance

This parameter simulates shifting weight to the left or right foot, by alternating the positional footstep force every other step. Use this to reduce or enhance the effect of "limping".

Rotation Balance

This parameter simulates shifting weight to the left or right foot, by alternating the angular footstep force every other step. Use this to reduce or enhance the effect of "limping".

声音(Sound)

Wield

This sound will be played when the weapon is being readied.

Unwield

This sound will be played when the weapon is being put away.

动画(Animation)

This foldout provides hooks for playing regular animations on a weapon model. Unity basically provides two ways of triggering animations on a simple model:

  1. Playing the clips from inside a single model (by animation clip).
  2. Playing the clips from separate model files (by file).

UFPS supports method 1. That means; for any model that has properly built-in animation clips, you can unfold it in the project view and select a clip , then drag it to an animation slot in the Inspector.

CHECKLIST:

  1. Always first make sure that the weapon model has animation clips in it after import.
  2. Then make sure the weapon prefab assigned under the vp_FPWeapon's 'Rendering' foldout has an 'Animation' component on it, which references all the clips you wish to play on the weapon.
  3. Only after this is properly set up, you can start filling the Animation foldouts of the vp_FPWeapon and vp_FPWeaponShooter components.
  4. Remember that these components can only use the very same animation clips that are listed in the unity Animation component.

For a brief explanation on the different use cases of regular animation versus procedural motion, see the 动画(Animation)s section of the Animation Concepts chapter.

Wield

An animation to be played on the weapon when it is readied.

Unwield

An animation to be played on the weapon when it is being put away.

Ambient

A random animation from this list will be played on the weapon automatically with random intervals. This is especially useful for alternating very subtle hand and finger movements, or temporarily removing the left hand when holding a rifle (as if to wipe it off) and can be a real realism and immersion factor!

Ambient Interval

Average random interval in seconds between ambient animations.

射击相关(Shooters)

The vp_FPWeaponShooter class adds firearm properties to a weapon. The component should be added to a weapon GameObject that already has a vp_FPWeapon component added to it. The script will manipulate the weapon component for recoil and manages firing rate, accuracy, sounds, muzzle flashes and spawning of projectiles and shell casings. It also has basic ammo and reloading features.

The weapon shooter class inherits from vp_Shooter, a generic firing class that can easily be used for other shooters in your world - AI soldiers, traps, helicopters, robotic turrets - you name it! Add a vp_Shooter component to give all these things the ability to fire projectiles with muzzle flashes and shell ejection.

Projectile

The Projectile foldout handles the birth aspects of any projectile objects spawned by the weapon.


Firing Rate

The normal firing rate of the weapon. If the player continuously presses down the fire button, shots will be fired using this as the minimum time interval in seconds.

Tap Firing Rate

The fastest possible firing rate of the weapon. If the player "spam clicks" the fire button (that is; presses and lets go of it many times in rapid succession) this will be the shortest allowed interval between bullets fired.

预制体 预设体 预制组件(Prefab)

This should be a gameobject with a projectile logic script added to it, such as vp_HitscanBullet. But remember that a projectile does not have to use a vp_HitscanBullet script. You could put any gameobject here and a copy of it will be spawned when the weapon is fired. Feel free to write your own crazy projectile components! For more information about creating a bullet prefab, see the 抛射体 子弹(Projectiles) chapter.

Gameobjects can not be saved using the preset system, so they need to be hooked manually each time you create a new vp_FPWeaponShooter component.

Scale

This parameter will scale each projectile object by the set amount. If using a vp_HitscanBullet projectile, this will be the scale of the resulting bullet hole object.


Count

The amount of projectiles to be fired simultaneously. Each projectile will get its own unique spread. However only one shell will be ejected and the muzzleflash will display as if one projectile was fired.


Spread

The conical deviation of the projectile. This parameter randomly alters the direction of the projectile by "Spread" degrees. A value of 1 means the projectile will deviate 1 degree within a cone from the player to the aim point. A value of 360 means the projectile will be emit from the player in a completely random direction (essentially within a sphere). This is good for scripting shotgun type weaponry or manipulating accuracy at runtime.

TIP: To emulate the famous Classic DOOM shotgun, set "Firing Rate" to 1, "Count" to 7, "Spread" to 6 and "Shell > Eject Delay" to 0.5. Oh yeah..

Spawn Delay

This is the delay between the fire button being pressed and a projectile is launched. Useful for weapons such as hand grenades, where you may want to play a short animation (i.e. pulling out the sprint) before the actual projectile is launched (or in this case thrown).

Motion

The Motion foldout contains parameters that manipulate the position and rotation of the weapon when discharged.

后坐力位置(Position Recoil)

A force added to the secondary position spring upon firing the weapon. Setting Z to a negative number will make the weapon increasingly "kick like a mule". Keep in mind that achieving a good positional recoil depends in large part on tweaking "Position > Spring2" of your vp_FPWeapon component. Check out the demo weapon presets for some example Spring2 Stiffness and Damping settings.

后坐力角度(Rotation Recoil)

A force added to the secondary rotation spring upon firing the weapon. Setting X to a negative number will make the weapon twist upward like a pistol. Rotation Recoil applied to the Z axis will make the weapon twist to the left or right for each shot fired (direction will be chosen randomly).

Keep in mind that achieving a good angular recoil depends in large part on tweaking the Rotation > Spring2 of your vp_FPWeapon component. Check out the demo weapon presets for some example Spring2 Stiffness and Damping settings.

Rotation Recoil Dead Zone

When using Rotation Recoil around the Z axis, this parameter can be used to tweak the aggressiveness of the recoil. The function works by limiting the minimum possible Z rotation applied. A high Dead Zone gives sharper / crazier Z twist.

Position Reset

Upon firing, the primary position spring will snap back to its rest state by this factor.

Rotation Reset

Upon firing, the primary position spring will snap back to its rest state by this factor. This can be used to make a weapon always fire in the forward direction regardless of current weapon angles.

Position Pause

Upon firing, any forces acting on the primary position spring will freeze and fade back in over this interval in seconds.

Rotation Pause

Upon firing, any forces acting on the primary rotation spring will freeze and fade back in over this interval in seconds. This is typically useful if the weapon has a pronounced Fall Sway and the player fires it in mid-air. Without a Rotation Pause, the weapon may fire upwards or sideways while falling.

空弹开火后坐力(Dry Fire Recoil)

This parameter multiplies the recoil value when the weapon is out of ammo. This can be used to simulate pulling the trigger with no discharge.

TIP: Make 'MotionDryFireRecoil' about -0.1 for a subtle out-of-ammo effect.

后坐力延迟(Recoil Delay)

This is the delay between the fire button being pressed and the recoil kicking in. Useful for weapons such as energy guns that may have a warmup animation prior to each shot being fired.


枪炮口的闪光(Muzzle Flash)

The Muzzle Flash foldout handles logic for displaying the weapon's 枪炮口的闪光(Muzzle Flash) (if any) and animating its rotation and opacity.


预制体 预设体 预制组件(Prefab)

This should be a mesh with a "Particles/Additive" shader and a vp_MuzzleFlash script added to it. For more information about creating a muzzle flash prefab, see the Muzzle Flashes chapter.

Gameobjects can not be saved using the preset system, so they need to be hooked manually each time you create a new vp_FPWeaponShooter component.

Position

Muzzle flash position offset relative to the FPCamera.

TIP: Set Position Z to a value larger than 0.5 to bring it into view.

Scale

This parameter will scale the muzzle flash object by the set amount.

Fade Speed

This amount of alpha will be deducted from the muzzle flash shader 60 times per second. When the weapon is discharged, the muzzle flash will be set to full alpha. It will then immediately start fading out at "Fade Speed". Note that the default (full) alpha for the "Particles/Additive" shader is 0.5.

枪炮口的闪光延迟(Muzzle Flash Delay)

This is the delay between the fire button being pressed and Muzzle Flash being shown. Useful for weapons such as energy guns that may have a warmup animation prior to each shot being fired.

Show Muzzle Flash

Toggles muzzle flash visualization on or off for editing purposes. The muzzle flash can only be visualized when the game is playing.

Set Position Z to a value larger than 0.5 to bring it into view.

Shell

The parameters under this foldout govern how shell casings are spawned and set in motion by the weapon.


预制体 预设体 预制组件(Prefab)

A gameobject that will be ejected from the weapon upon firing. This should be a mesh with a vp_Shell script added to it. For more information about creating a shell prefab, see the 弹壳(Shells) chapter.

Gameobjects can not be saved using the preset system, so they need to be hooked manually each time you create a new vp_FPWeaponShooter component.

Scale

This parameter will scale each ejected shell object by the set amount.

弹出位置(Eject Position)

Shell eject position offset relative to the FPCamera.

Set Position Z to atleast 0.5 to bring it into view.

弹射方向(Eject Direction)

The vector in relation to the FPCamera, along which 弹壳(Shells) will be ejected from the Eject Position. To send a shell flying forward, upward and to the right, set Eject Direction to 1, 1, 1.

弹射速度(Eject Velocity)

The amount of force (positional speed) added to the shell's rigidbody object when instantiated. This is what sends the shell flying.

弹射线路(Eject Spin)

When a shell is instantiated it receives a completely random torque (rotation speed, or spin). This parameter scales the spin. A value of 0 means the shell won't spin at all. A value of 1 means it will spin like crazy.

弹射延迟(Eject Delay)

Time to wait before ejecting the shell after firing. This is very useful for i.e. shotguns and grenade launchers. For example, you could use a traditional animation for a pump action shotgun, and sync "Eject Delay" to the animation.


声音(Sound)

The Sound foldout defines how the shooter sounds when fired.


火焰(Fire)

The standard firing sound of the weapon.

Gameobjects can not be saved using the preset system, so they need to be hooked manually each time you create a new vp_FPWeaponShooter component.

空弹开火(Dry Fire)

This sound is played if the player attempts to fire when the weapon is out of ammo.

Fire Pitch

This parameter optionally pitches the sound of each shot fired slightly different to get a more organic firing sound. Variations in pitch should be kept minimal. A typical Min-Max range would be 0.95-1.05. This parameter allows you to use the same audio file with different pitch for different weapons.

Fire Sound Delay

This is the delay between the fire button being pressed and the fire sound being played.

动画(Animation)

The 动画(Animation) foldout contains any animations to be played on the weapon by the shooter component.

TIP: For many weapons (especially firearms with no prominent moving parts) you can often get a long way by just using recoil forces.

For a checklist of the steps needed to play animations on a weapon model, see Weapons > Animation.

For more info about the different use cases of procedural motion versus regular animation, see the chapters Animation Concepts > Animations.

火焰(Fire)

An animation to be played on the weapon when it is discharged. Fire animations are useful for things like pump action shotguns or a bow and arrow, where you really want more stuff going on than just force recoil.

近战攻击(Melee Attacks)

The vp_FPWeaponMeleeAttack component can be used to generate super-fluid melee animations that blend dynamically between each other and react to the environment and forces affecting the player. The system was originally devised to see whether melee combat would be feasible using only spring physics and entirely without traditional animation. It worked out quite well.

For example: If you swing about a melee weapon while running, jumping or falling, the weapon will animate very organically, affected by character velocity as if carried by real, elastic muscles. If you stand close to an explosion, your arm will twist almost as if you're about to loose hold of the weapon. If you hit a solid object, the weapon will stop and bounce back.

Arguably, it would be hard to get these things going at the same level of quality using only traditional animation. However, this system is still in an experimental stage and certainly not the easiest to use! It has been included in the package by popular demand. But rest assured: Here Be Dragons ;)

Tutorial (Basic)

The quickest way to set up a new melee weapon

The quickest way is simply duplicating the existing demo mace, which has a range of melee swings that should work for most prototype purposes.

  1. Open DemoScene1
  2. Unfold the player and camera components and select "4Mace"


  3. Drag it into your project view somewhere to create a prefab
  4. Open another scene with an fps player, for example "cleanscene"
  5. Drag the mace prefab to the camera object of the player
  6. Done. Now you can just change the mesh and sound fx in the Inspector to get your own melee weapons going.

Making adjustments

System Walkthrough

The melee attack system uses a quite complex state setup. Before you move on, you will want to have a thorough understanding of UFPS 状态(States) and presets. It's also a very good idea to have a look at how the mace and its components are set up in DemoScene1 to get a feeling for how everything is put together. You may also want to study the comments in the melee attack script.

To quickly get a grasp of what's going on, the following walkthrough might help.

Weapon poses

  1. Load DemoScene 1 and press Play.
  2. Go to the second screen, "EXAMPLES", and select the "Barbarian" demo preset.
  3. At the top of the Hierarchy, find the "DemoPlayer" object, unfold its "FPSCamera" child and select the "4Mace" weapon object childed under "4MaceTransform".

  1. Unfold the "vp_FPWeapon" component of the mace and unfold its "States" list (make sure you're in the weapon component and not the weapon melee attack component under it).


  2. In the state list, click on the state named "SwingLeft".
  3. Then toggle the state named "PullRight" on and off while watching the first person game view.

As you can see the mace weapon component has a bunch of states for various poses that might come in handy during melee combat. Toggling them will move the mace by having its springs act like muscles blending between the positions.

However, the motion does not happen automatically (you need to toggle it manually) and the movement is quite sluggish and not very violent. Also, nothing will happen if you hit something. We need to add timing, collision detection, impact effects and violent forces! This is the purpose of the vp_FPWeaponMeleeAttack component.

Attack states

  1. In the Inspector, with the "States" foldout still open, scroll down and unfold the "vp_FPWeaponMeleeAttack" component.
  2. Uncheck the "Pick a random state for each attack" checkbox and open the "States" foldout right above it.


  3. Click on one of the states in the state list, whose names begin with "To" ... (any one except the Default state).
  4. Go to the game view and click the left mouse button. The mace should get swung in the direction you chose. No matter how many times you swing the mace, it gets swung in the same direction. Also, this time around the motion is more violent and there are sound effects. If you hit something, the mace will repel, spawn particles and (in case it was a physics object), add forces to the target.
  5. Go back down and check the "Pick a random state for each attack" checkbox.
  6. Unfold the "Weapon States" tab at the top of the same (FPWeaponMeleeAttack) component.
  7. Again, fire repeatedly and watch the bottom "States" list along with the top "Pull" and "Swing" slots while doing so.

What happens here is that a random melee attack state gets selected every time you press fire. Also, a corresponding "Pull" and a "Swing" state gets enabled. Importantly, they do not get enabled on this (melee attack) component, but on the above weapon component. Also, the states get enabled with a slight delay inbetween them. On top of this, soft angular and positional forces are added to make the motion more dramatic.

  1. Scroll the Inspector so you can see both the unfolded weapon "States" and the unfolded melee attack "States" at the same time.
  2. Go back to the game and press and hold the left mouse button. Watch how the two components work together to manipulate the weapon springs of the mace.

The melee attack sequence

When a melee attack is initiated, this is what happens under the hood:

  1. A random Attack state is chosen on the melee attack component.
  2. The Pull state of the chosen Attack is enabled on the weapon component, moving the weapon back in preparation of attack.
  3. A delay is imposed by the melee attack component. Basically, this is to give the weapon time to pull back before getting swung.
  4. The Swing state of the chosen Attack is enabled on the weapon component. This will make the weapon transition to its final angle.
  5. In order for the transition to become more fast and violent, angular and positional forces are applied to the weapon component.
  6. After a very short delay (about half-way through the attack) a check is done to see if we're hitting anything. If so, particles and damage take effect.
  7. If we hit something, the Swing state is interrupted and the weapon is reset and goes back to its rest state.

Types of states

The system uses 3 types of states. The melee attack component can have an unlimited amount of Attack states, each referencing two states on the weapon component: the Pull state (for raising the weapon) and the Swing state (for slashing). Attacks and their sub-states are alternated randomly when the player holds the attack button. In other words:

Pull

A regular weapon state for pulling back the weapon and gathering force in preparation of the attack. Sits on the weapon component.

Swing

The final orientation of the weapon at the end of the attack (striking / thrusting / slashing). Sits on the weapon component.

Attack

This state generates animation sequences by handling timing, physics and the enabling & disabling of the above states on the weapon component. It sits on the melee attack component.

Default

The regular, bottom-most state of any vp_Component. On the vp_FPWeaponMeleeAttack object, this state is only intended to be used at the design stage. Unless a weapon only has one single attack, each attacks should use a custom state.

Tutorial (Advanced)

Overview

There are basically three stages to designing a melee attack:

  1. Begin by designing its Pull and Swing poses as togglable states on the weapon component.
  2. You then design the motions, forces and effects that go along with those states. This work is done on the Default state of the melee attack component.
  3. The melee attack state is saved to a new preset, then added to the state list of the melee attack component where it can be activated randomly or specifically at runtime.

Workflow

1. Decide how the weapon should move

For this example, we'll create an "up-right to down-left" sword swing. This could be visualized as raising a sword to above your right shoulder then slicing your opponent diagonally from his left shoulder to his right hip.

2. Create the Pull state

Go into you weapon component, open the Position and Rotation foldouts and modify the position and orientation of the weapon until it is raised to the right of - and above - the camera, pointing over your shoulder. Save this tweak by clicking the Preset -> Save Tweaks button (will create a new preset text file containing only the parameters that you have changed). Name this Pull state something fitting, For example "PullUpRight".

TIPS:

  1. You may want to modify the Rendering -> Clipping Planes parameter in case the model gets too close to the camera.
  2. Modifying the pivot position and angle of the model can be used to create more complex motions.

3. Create the Swing state

Same process. Go into you weapon component and modify its Position, Rotation and Rendering settings until the weapon is pointed forward and sits below and to the left of the camera. Save the preset as, e.g. "SwingDownLeft".

4. Assign the states to the weapon component

Add two new states and name them, e.g. "PullUpRight" and "SwingDownLeft". Drag your new presets to the corresponding slots.

5. Create the attack script

Go to the FPWeaponMeleeAttack component and disable "Pick a random state for each attack". This allows you to design an attack using the "Default" state, that is; without other states getting enabled randomly, which may be interrupting and confusing.

IMPORTANT: Make sure the Weapon States foldout has the correct names for the Pull and Swing states you just created on the weapon.

TIP: You can also start off by duplicating an existing attack. In the project view, right click on a melee attack state and select Duplicate. Rename the new script and open it in a text editor. Don't forget to update the names of the WeaponStatePull and WeaponStateSwing with the names of your new pull and swing states.

6. Create an Attack state

Save the state as a new preset. When done, open the "States" foldout, click "Add State" and assign the preset you just saved. It doesn't really matter what you name the states on the melee attack component, unless you mean to enable these states from code later rather than use the random logic. The important thing is that the "Pull" and "Swing" fields in each preset correspond to actual states on the weapon component.

7. Test the attack in-game

As you get more and more weapon poses and melee attack states that use them, the "random attack" mode will become more and more organic and entertaining.

8. Tweak the swing motion

... in the attack script to adjust the speed / violence of the swing. The "SwingPositionSoftForce" and "SwingRotationSoftForce" parameters will add force to the weapon over several frames, the amount of which is determined by "SwingSoftForceFrames". The fewer frames, the more instant the attack will appear. It is recommended to keep it at the default value for smooth motion, and instead regulating the force of the attack using the force parameters.

9. Tweak the recoil force

The recoil force is an impulse that takes effect whenever the weapon hits a solid object such as an enemy or a concrete wall. Typically, the recoil force should be roughly the inverse of the swing force. For example: if the weapon travels left across the screen and hits something, it should repel back to the right.

10. Tweak the physics force

This force is applied to any rigid bodies that we hit. The direction of the force is currently always straight away from the player. The "DamageForce" parameter simply determines the strength of the force impulse.

With the random state checkbox unchecked, you can control which attack gets played by setting the state of the melee attack component from script. For example, you may want to bind a specific slash to a certain button.

Debug objects

When you perform melee attacks with the vp_FPWeaponMeleeAttack's "Swing Motion" foldout open in the Inspector, red and yellow spheres will appear. The big (yellow) spheres show where the spherecast used for collision detection spawns. In reality, it is not made up of spheres, but is a wide, continuous tube. The small (red) sphere shows where the spherecast detects a collision with the environment.

This concludes the docs for the experimental UFPS melee system! As you may have noticed the workflow can be a bit challenging :) but the end result can sometimes be really cool. Hope you'll have fun with it!

角色身体(Player Body)

UFPS comes loaded with player body features, designed for characters with a need to move around and fire guns a lot! Its weapon spring physics make for a novel mix between traditional animation (body) and procedural animation (1st person arms and weapon). The feature set can be divided into five categories, all explained in the following chapters.

Features Overview

Body animator with headlook

The UFPS player event system connected to a Mecanim animator controller, along with specialized body orientation and headlook features.

Full body awareness

Systems to provide the experience of being a human within a body (and not just a floating camera).

3rd person camera view

An experimental "survival horror-style" over-the-shoulder camera view, with logic to make guns fire at the camera's look point.

Hand-aiming & recoil

The rotating of a hand to make it aim a weapon correctly, and the propagation of recoil force from the weapon onto the hand.

Ragdoll handling

The physics-based animation of a human body when a player gets killed and falls to the ground / gets tossed away.

Body animator with headlook

UFPS has its own animator scripts with a headlook logic specialized for gunplay. The headlook animates bone falloffs within the spine according to player states in very lifelike ways.

For example: if you look around without firing or aiming, you head will turn flexibly and freely of your torso. This gives the appearance of a character that is "alertly" scanning the environment around it. The second you aim or fire, the torso and arm will "stiffen up" and turn to where your head is pointed, aiming the gun there. This quite effectively communicates a sudden interest in a world look point. Lower body (legs and feet) rotate independently of the upper body (spine, arms and head). For example: the character can stand still and look around quite freely without moving its feet.

These animator scripts are tightly integrated with the UFPS player event system and designed for use with the provided "UFPSExampleAnimator" Mecanim controller. When an UFPS vp_Activity event starts or stops, a corresponding parameter gets activated in Mecanim, blending the animations into that state. The body animator also maintains floating point values (moving, turning, pitching and jumping), triggers (climbing, reloading, sliding out of control) and info on the weapon type (firearm, melee) and grip (one handed, two handed) for Mecanim to play suitable animations.

Full body awareness

UFPS allows you to look down at your body as you walk, fight, crouch, run and jump around in first person. Since there is such a strong emphasis on wild, spring based camera motions, extra care is taken to keep the camera in sync with your 3d head, making sure the camera view doesn't clip the body model, all while allowing the camera to move around as freely as possible.

In 1st person the material of the 3rd person head and arms is set to an invisible, shadow casting material in order not to clip the camera or interfere with 1st person arms and weapons. If you unwield the current weapon, the Mecanim arms will come back into visibility for walking and sprinting.

Furthermore, the weapon class has logic to procedurally and smoothly move weapons into realistic positions when looking down. When you switch back to 3rd person, the head and arms reassume their original materials and the bodyanimator exchanges some aspects of it logic for movement that looks better in 3rd person.

All in all complicated stuff, and very effectful when it comes together!

Note: When playing in 1st person in the editor, you will spot this guy bouncing around in the Scene view, arms flying everywhere and legs sticking through the ground. Not to worry! This is not how the character will appear in 3rd person or multiplayer - it's just the full body awareness systems at work and this will never be rendered into the actual game.

Nevermind the "headless dude" ...

3rd person camera view

This experimental feature provides a "survival horror-style" camera that collides with the environment, reacts to explosions and allows for some pretty action packed precision gunplay (this feature was originally a by-product of testing the body systems, but turned into a decent feature of its own).

While this works really well with camera-to-level collision and certainly opens the door to your own Tomb Raiders, Resident Evils and MMOs, it is far from glitch-free at time of writing, and for the time being provided as-is, for animation testing purposes and as a starting point for those who may be interested in developing it further.

Except for arms, the 1st and 3rd person player models are actually one and the same. When you switch to 3rd person, the head and arms again become visible and the bodyanimator exchanges some aspects of its logic for motion that looks better in 3rd person.

TIP: For an example of player appearance in 3rd person, open up the "DemoScene3" or "SkyCity" level and press the "Toggle3rdPerson" key

(default: "V").

Hand-aiming & recoil

"Cosmetic" precision aiming is taken care of by a simple script that sits on the player's right hand, rotating it to keep the weapon aimed at the player's look point. This has no real gameplay effect (bullet precision is regulated in the shooter script) but it makes things look fairly alive and "realistic". This aiming script also applies the current weapon's recoil when shooting which is quite cool.

Note that this subset of the body system is still in an early prototype state. The feature is currently "rough around the edges" and quite challenging to calibrate but it gets the job done when setup right.

Ragdoll handling

"Ragdolling" is always lots of fun and very entertaining in action, especially with a suitable application of high explosives! When ragdolling is enabled in UFPS, the body of any killed player will crash to the ground or get tossed away in a "physically realistic" manner adapted to the current situation. Keep in mind that the ragdoll handler doesn't set up a ragdoll for you (the ragdoll components must be added to you character model by means of the Unity ragdoll wizard or some other method).

What it does do is initialize things on startup, enable the ragdoll on death and disable it on respawn. There is also the "VelocityMultiplier", which has the momentum of the charactercontroller carry over into velocity on the ragdoll upon death. This can have quite cool and sometimes hilarious results :).

Player Body Setup

Introduction

To create a brand new player completely from scratch it is easiest to start with an existing (body-less) player prefab. If you want to set up a basic, functioning player for learning purposes, you may want to study this chapter before tackling full player bodies.

The full animated player body system - between UFPS and Mecanim - is really a quite complex beast in total. Good news is: for the most part it's a one-time process per character!

The "Body" child object

The main difference between a basic UFPS player setup and one with a body, is that in addition to the "FPSCamera" child object, the latter also has a "Body" child gameobject. (Edit: in the first release of 1.4.8 this is actually named "Hero".) This object basically contains an animated player model at the local position and rotation (0, 0, 0).

"Weapons" vs. "weapon props"

In UFPS there are two objects for each weapon, a "real" one for 1st person and a "prop" for 3rd person. The 1st person weapon object manages all the game logic and fx. The 3rd person weapon is only a cosmetical one for 3rd person views, AI and multiplayer remote players. That said, spring-based recoil from the vp_FPWeapon can be made to affect the hand and weapon of your 3rd person body model by means of the vp_3rdPersonWeaponAim component.

When you toggle to 3rd person, the 1st person weapon becomes invisible and begins firing any bullets from the world position of the (now visible) 3rd person weapon props. Behind the scenes, though, it is always the same vp_FPWeapons and vp_FPShooters that take care of all the logical dirty work, including accuracy, projectile / shell spawning, muzzleflashes and so on.

Good to know for Artists

Study the Hero player hierarchy in the DemoScene3 and SkyCity maps, aswell as this section on player body anatomy.

Good to know for Scripters

Study the comments in the vp_BodyAnimator and vp_FPBodyAnimator scripts along with the player setup in the scenes, aswell as this section with body scripting notes.

Tutorials

Setting up a basic, ragdolled player body

  1. Begin with a fully working UFPS player without a body, such as the "AdvancedPlayer". You can also set one up from scratch (see this chapter).

  1. Acquire a skinned, Mecanim-ready body model with an avatar. A good place to start is the Unity Asset Store.

  1. Always begin by applying ragdoll components (colliders, joints, rigidbodies) to the model. This can be done using Unity's built-in ragdoll wizard.
  2. Place the free-floating body over a floor collider to make sure it "ragdolls" properly. You can test this by starting and stopping the game a few times while studying the body model in the Scene view.

  1. Name the body object "Body" and make it a child of the root player object (for example: "AdvancedPlayer").

  1. Make sure the body's local position and rotation is (0, 0, 0).

  • IMPORTANT: If the body's local position and rotation is not (0, 0, 0) it will not be attached properly to the charactercontroller.
  • The scale of the Body child object would usually be kept at (1, 1, 1) but can actually be set to any scale you like. Please remember that this is not true for the main player gameobject. For information about scaling the main player gameobject (in the case of giants, dinos, children, hobbits) see this help post.

Start the game and hit the "Toggle3rdPerson" key (default: "V"). The player should now have a basic - albeit stiff - body attached to charactercontroller as it moves around in the scene. To make it animate and ragdoll in response to game events, please see the next tutorial.

Enabling animation, headlook and ragdoll handler

  1. Assign a Mecanim "Animator" component to the "Body" gameobject.

  1. In the "Controller" slot, assign the default "UFPSExampleAnimator".

  1. In the "Avatar" slot, assign a Mecanim avatar that was created for your model.

  1. Root motion should always be set to OFF, or the body model could start walking away from your charactercontroller.

  1. Assign a vp_FPBodyAnimator component to the "Body" gameobject.

  1. Time to configure the animator for headlook. With the "Body" object's vp_FPBodyAnimator visible in the Inspector, unfold the hierarchy until you find the head bone of the character (usually an object named "Head"). Drag this gameobject from the Hierarchy view to the Head Bone slot of the vp_FPBodyAnimator component.

  1. Look a little bit further up the hierarchy to locate the lowest spine bone. The bone directly above the hips / pelvis is usually what works best (likely an object with "Spine" in its name). Drag this gameobject from the Hierarchy view to the Lowest Spine Bone slot of the vp_FPBodyAnimator component.

  1. For now, leave all remaining settings of the vp_FPBodyAnimator at their defaults.

  1. Add a vp_RagdollHandler component to the "Body" gameobject and assign the model's head gameobject to the "Head Bone" slot.

  1. Time to take the animated character for a test drive! Start the game and hit the "Toggle3rdPerson" key (default: "V") and hopefully the player is now moving its arms and legs in response to input, aswell as "ragdolling" when it dies.

Done! Toggle back to 1st person, and you will likely find that the player has too many arms in the 1st person view. Perhaps you can even see the inside of the player model's head (teeth, tongue, eyballs and whatnot). To fix this see the following section.

Removing head clipping and extra arms

If your player appears to have too many arms or you can see inside of the player model's head, you need to make the body model's head and arms invisible in the 1st person view. This can be done in two ways. Here is the easiest one:

  1. Go to the Hierarchy view and select the head and upper right arm bones (gameobjects) of your player.

  1. Give these bones each a scale of (0, 0, 0).

  1. That's it! Head clipping and extra arms should now be resolved for basic 1st person testing.

This quick-fix will not currently work in 3rd person, will break ragdolls and will cause your head and arms to cast no shadows. To solve all of this the proper (but more labor intensive) way please see this tutorial.

Adding weapon props for 3rd person

  1. Unfold your body hierarchy until you find the right hand gameobject, and create a child gameobject under it (alongside the finger bones) named "Weapons". Make sure the new gameobject's local position and rotation is (0, 0, 0). The right hand bone can usually be found under a spine bone -> right shoulder -> right arm and so on down the hierarchy.

  1. Now, for every one of your 1st person weapons (that should also be visible in 3rd person):
  1. Create a child gameobject under the right hand "Weapons" child. Name it the same as the corresponding 1st person weapon. Make sure this gameobject's local position and rotation is (0, 0, 0).
  2. Add the following components to the new 3rd person weapon:
  1. Set up the mesh filter and mesh render to display a 3rd person prop for your 1st person weapon.

TIP: The typical 1st person weapon model is unsuitable for 3rd person because it has animated arms on it. Also, 1st person weapons may be way too highly detailed to be appropriate for AI or multiplayer remote players. Re-using pickup gameobjects can often be a time saver for creating 3rd person weapons. The model and shader can usually stay the same (as long as there are no arms).

Just be sure to
remove any and all pickup components from the gameobject (Sphere Collider, Audio Source, Rigidbody, Box Collider, vp_ItemPickup, vp_Respawner). This is very important to avoid strange gameplay bugs.

Basically, the only remaining components on the 3rd person weapon object (at this point in the tutorial) should be a
Mesh Renderer and a Mesh Filter.

If you start the game now you will notice the player having one or more weapons in its hand. However, the weapons are active always, many at a time, and have no logical connection to their 1st person counterparts. They may also be pointing in all sorts of directions. We need to adjust position and rotation of the weapons.

Adjusting the position and rotation of weapon props

For each weapon prop in turn:

  1. Disable all weapon props except the one you wish to tweak.

  1. Select the first weapon prop and press "F" (this will focus editor scaling and rotation to that weapon which is essential for the task).

  1. Position the weapon so that it sits as snugly / realistically in the character's open hand as possible. The straight index finger should be in line with the trigger. The pistol grip should sit firmly between the base of the thumb and index finger.

TIP: After you have positioned the first weapon prop, you can often just copy position and rotation onto the remaining ones (assuming the models have similar pivot points). To do so, click the little cog wheel of the first weapon's Transform component -> "Copy Component". Then in the Transform component of the next weapon, cog wheel -> "Paste Component Values". This will give you decent positioning for all weapons in a second with only minor tweaks remaining!

IMPORTANT: When done tweaking weapon positions, always make sure to enable all the weapons before you press play. Otherwise their aiming logic could break later. Basically, whenever the game is not playing, in the editor the character should always have a "bundle of guns" in its hand. These will be hidden on startup by the WeaponHandler.

  1. Adjust the transform scale of the weapon if needed. Sometimes this is essential for a realistic grip (scaling of 3rd person weapon props will have no effect on gameplay logic).

  1. Go to the corresponding vp_FPWeapon (childed to the main FPS camera) and unfold its "Rendering" foldout.

  1. Drag the scene gameobject of the 3rd person weapon prop into the "Rendering" -> "3rdPersonWeapon" slot. This will tell UFPS which 3rd person weapon prop to enable when the camera view is toggled from 1st to 3rd person.

Start the game and temporarily disable the player's inventory component for access to all weapons. As you toggle weapons, the player should now hold each weapon properly in its hand. Muzzleflashes and shells ejection may be slightly off, though. Read on to fix this ...

Defining spawnpoints for muzzleflashes and shell casings

If you see muzzleflashes and shells spawning at the wrong positions, you need to create, position and orient "Muzzle" and "Shell" child gameobjects for your weapon props.

枪炮口的闪光(Muzzle Flash)
  1. Create an empty gameobject, name it "Muzzle" and make it a child of the weapon prop.

  1. Set the muzzle transform's localPosition to (0, 0, 0) and then tweak the position until the arrow origin is located ever so slightly in front of the muzzle of the gun.

  1. Set the localRotation to (0, 0, 0) and then tweak it if necessary until the Z axis (blue arrow) points in the exact firing direction of the weapon.

Shell ejection
  1. Create an empty gameobject, name it "Shell" and make it a child of the weapon prop.

  1. Set the shell transform's localPosition to (0, 0, 0) and then tweak the position until the arrow origin is located in the middle of the weapon's shell ejection port.

  1. Set the localRotation to (0, 0, 0) and then tweak it if necessary until the Z axis (blue arrow) points in the direction that you want the shells to fly when firing.

Re-using weapon groups

After you have created a "Weapon" group for one character, you can duplicate and re-use that weapon group on characters that should carry the same arsenal. You may need to reposition the weapons in their hands and you will need to reconnect the weapon props with their new host vp_FPWeapons, but atleast you can save a few minutes of little work this way.

Ok, so far we've covered mosts steps needed to create working 3rd person weapons! However, at this point you will have probably noticed the weapons pointing in slightly different directions from where bullets hit when firing. To fix this see the following tutorial ...

Calibrating 3rd person weapon aim

By default, weapon aiming of the player model is a result of the Mecanim animation used. Along with headlook this will make the arms and weapon point in roughly the right direction (just not right enough to look good in 3rd person).

The vp_3rdPersonWeaponAim component can be used to make a character's main hand + weapon aim more accurately at the screen crosshair. This component also imposes recoil from the active vp_FPWeapon onto the hand of the player model, which looks really cool.

DISCLAIMER: This subset of the body system is still in a prototype state. Logic and workflow is far from ideal and full of lore. Here be dragons!

Please note that melee weapons do not need a vp_3rdPersonWeaponAim component, since they have no need for projectile recoil or aiming.

Preparation checklist
  1. Make sure that you can see the Game View and Scene view simultaneously while playing the game. Also, make sure to not use the "Maximize on play" mode.

  1. Make sure the parent of the 3rd person "Weapons" group is the right hand bone of the character and that its name has the letters "hand" in it. If the name does not, fix this or drag the hand object into the vp_3rdPersonWeaponAim component's "Hand" slot in the Inspector.

  1. Disable the player's vp_PlayerInventory component for access to all weapons while editing.

  1. Always make sure that all the 3rd person weapon props are enabled before you press play (this goes not just for this tutorial, but is always true). Otherwise aiming logic will fail to initialize.

Calibration steps
  1. Select your target 3rd person weapon prop and assign a vp_3rdPersonWeaponAim component to it.

  1. Start the game and hit the "Toggle3rdPerson" key (default: "V").

  1. Select the root player object in the Hierarchy view so that it becomes visible in the Inspector.

  1. Go to the Game view and turn the player around using mouselook until its transform rotation in the Inspector is roughly (0, 0, 0).

  1. Select the target weapon prop object and, in the Inspector, unfold its vp_3rdPersonWeaponAim component.

  1. Scroll down a bit to enable "Keep Aiming". Then go to the Game view, wield the weapon and press the Zoom key (default: right mouse button) to make the player raise its weapon. As long as "Keep Aiming" is enabled the weapon should now remain in the aim state, making tweaking much, much easier.

  1. There is a fair chance the weapon is now being pointed in a completely wrong or even painful direction! Set all of the "Angle Adjust" sliders to "180".

  1. With the weapon prop gameobject selected in the Hierarchy view, press "F" in the Scene view to make the editor focus on the weapon.

  1. Click on the "Z" arm of the Scene Gizmo. Then click the middle of the Scene Gizmo to enable Isometric Mode.

  1. Adjust the Scene view to get a good look of the character from its waist up. Then go back to the current weapon's vp_3rdPersonWeaponAim Inspector and test each slider in turn to find the slider that rolls the hand (that is - rotates it in the way you would if you were to hold out your hand, palm facing the ground, then turned your palm up to see if it was raining).


This could be a different slider for different models and depends on various factors during rigging and export from various 3d art programs.


Restore the other sliders to "
180" then roll the hand until the gun's "top" faces upward properly in the Game view.

  1. Click on the "X" arm of the Scene Gizmo. Then use the remaining two sliders to make the gun face straight forward (pitch, yaw).

  1. If you look around in the Game view now, the character should face the gun more accurately at things. However aim could likely use some fine-calibration.

  1. Look down and fire a shot into the ground about half a meter in front of and to the right of the character. Then aim the crosshair precisely at the resulting bullet hole.

  1. If the gun doesn't point satisfyingly at the bullet hole, make small adjustments to the "Angle Adjust" sliders until it does.

TIP: Any time you want to toggle back and forth between the Inspector and the Game view without firing shots, press ESC to free the mouse cursor from the game, and the right mouse button on top of the Game view to reenable mouselook without firing.

IMPORTANT: When you're happy with the aim, do not stop the game before copying the component values, or your tweaks will be lost! Read on ...

  1. To save your values, click the little cog wheel  of the vp_3rdPersonWeaponAim component -> "Copy Component". Now you can stop the game.

  1. After stopping the game, again click the cog wheel  -> "Paste Component Values".

  1. Done! Your weapon should now point accurately at targets in 3rd person (unless they get really, really close). Don't forget to set the Scene Gizmo back to Perspective Mode if so desired. See the following tutorial for info on how to adjust recoil.

Adjusting 3rd person Recoil

First make sure that your weapon prop has a vp_3rdPersonWeaponAim component (see this tutorial for information on how to set one up).

  1. Make sure your 3rd person weapon is hooked to a 1st person one, and that the 1st person weapon has visible recoil.

  1. Start the game and hit the "Toggle3rdPerson" key (default: "V").

  1. In the Hierarchy view, select the target weapon prop object (under the character's right hand "Weapon" group).

  1. In the Inspector, unfold the vp_3rdPersonWeaponAim component and locate the "Recoil Factor" sliders.

  1. Fire the weapon and observe how the weapon moves. The recoil applied around the various axes in 1st person may not be suitable for 3rd person and the weapon may recoil too much or too little.

  1. Adjust the sliders until things look right in 3rd person. To enhance recoil, increase the value, to invert it use a negative value. To disable recoil around a vector entirely, set the corresponding slider to "0".

Head & Arm materials setup

When you first add a plain human body model to an FPS player, usually you can see too many arms in 1st person plus the inside of the player model's head (teeth, tongue, eyeballs).

To fix this, the head must be made invisible at all times in 1st person, and the arms must be made invisible when wielding any 1st person weapons that come with their own arms.

This result can be temporarily achieved using the "cheat" described here, however that's a quick fix resulting in several unintended glitches, making it useful only for prototyping and quick tests.

UFPS can solve the issue "properly" by applying a little black magic to make the arm and head meshes invisible although still casting shadows in the 3d world. For this to work your player model needs to have one material assignment for the head, one for the arms and one for the rest of the body.

TIP: The following tutorial can be done by hand, but there is also a great add-on asset for UFPS by CodeBison, called FPS Mesh Tool. This excellent piece of software will take care of all the below steps for you and a whole lot more (no need for a standalone art program).


For any new player model you want to use for 1st person:

  1. Open the body model in a 3d art program and split it up so that the head has its own material slot, the arms sharing one material slot, and the rest of the body has one material slot.

  1. In Unity, on the SkinnedMeshRenderer of the body model, assign any material you like to the "Body".

  1. Assign two separate materials to the "Arm" and "Head" slots. Make sure the names of these materials have "head" and "arm" in them, respectively (case insensitive).

  1. Verify that the player body's vp_FPBodyAnimator component has the default UFPS "InvisibleShadowCaster" material assigned to it.

Now, in 1st person mode, the inside of your head should be invisible (like in the real world ;) and there should be no more cases of "too many arms". Toggling to 3rd person view should make the head and arms come instantly back into visibilty, everything in a seamless manner.

The character can of course have many more materials too if you like. What's important is that the arms share a material with the letters "arm" in the name inside Unity, and that the head has a material of its own with the word "head" in its name.

Anatomy of a player body

The following image provides an overview of the functional aspects of a body hierarchy (script components in white):

1) The main Body object, childed to the root player gameobject

Components

On a local, 1st or 3rd (!) person player the animator is always of type vp_FPBodyAnimator, but on a computer controlled AI / bot or multiplayer remote player, it would instead be a vp_BodyAnimator (without the "FP"). This is because any script prefixed "vp_FP" will assume a camera (rendering to a monitor) and input (e.g. mouse and keyboard)

2) The Skinned Mesh Renderer

This is a regular Unity SkinnedMeshRenderer component with three materials for preventing clipping and multiple arms in 1st person. These are manipulated by the bodyanimator script. Basically, when you are in 1st person the "Head" and "Arm" materials are replaced by an invisible, shadow casting shader. If you go unarmed in 1st person, the "Mecanim arms" are again shown (optional). When you toggle to 3rd person these get replaced by a normal material. See this tutorial for info on how to set up body materials.

3) The "Lowest Spine Bone", assigned to slot in the bodyanimator (1)

Used in headlook logic. This could be a uniquely named and located gameobject in every model, but the bone directly above the hips / pelvis is usually what works best.

4) The "Head Bone" assigned to slot in the bodyanimator (1)

Used in headlook logic. This could be a uniquely named and located gameobject in every model, but the bone located as close as possible to the center of the body model's head is usually what works best.

All bones in the hierarchy in direct ascension between this gameobject and the "Head Bone" gameobject will be considered the character's spine (hence the bent, red line in the illustration) and will be automatically included in the headlook mechanism. In the above illustration the bones included will be "Spine", "Spine1", "Spine2", "Spine3", "Neck" and "Head".

The bones "LeftShoulder" and "RightShoulder" in this illustration are not directly rotated by headlook since they are not a parent of "Head". However, as children of "Spine3" they'll still be affected by headlook logic. The arms will turn roughly in the direction the player is aiming, and the animation and weapon aiming scripts will kick in to achieve the last part of a spot-on aim.

5) Right hand gameobject (parent of 3rd person weapons)

This is usually an empty gameobject (no components), but you will navigate to it many times because it is the parent of all the 3rd person weapons (6).

This could be a uniquely named and located gameobject in every model, but it's a very good idea for this object to have the letters "hand" (case insensitive) in its name because of an auto-initialization feature of the weapon aiming script.

6) The Weapon Group

The 3rd person weapon group is an empty gameobject (no components) that contains visual (as opposed to "functional") representations of the 1st person weapons that are childed to the main FPS camera. These are associated with a  vp_FPWeapon under its "Rendering" -> "3rd Person Weapon Model" slot.

7) 3rd Person Weapon Models

These are separate "prop" models depicting 1st person weapons for 3rd person views, AI and multiplayer remote players. Note that the 1st person weapon object still manages all the game logic and fx. In 3rd person, the 1st person weapon is invisible and fires any bullets from the world position of its corresponding 3rd person weapon prop. See this tutorial for info on how to set up 3rd person weapon props.

Mecanim Reference

The vp_BodyAnimator and vp_FPBodyAnimator scripts are tightly integrated with the UFPS player event system and designed for use with the provided "UFPSExampleAnimator" Mecanim controller. In the UFPS demo scenes, whenever a UFPS vp_Activity event starts or stops, a corresponding parameter gets activated in Mecanim, blending the animations into that state.

PLEASE NOTE: Working with these statemachines will require a decent understanding of Unity's animation system, Mecanim, which is outside the scope of this manual. To learn about Mecanim please see these links:

Upper and lower body split

The system assumes an upright player, logically divided into upper and lower body. The UFPSExampleAnimator has three layers: "Base", "Lower Body" and "Upper Body". The lower and upper body layers each have elaborate state machine setups designed for movement and gunplay, respectively. The base layer is currently kept empty and could be used for expanding the system.

Most of the example animation states submit to this upper / lower body split. For example: legs will frequently be running while the upper body is reloading and one doesn't really get affected by what the other is up to.

To open up the Animator window for your player, select its "Body" gameobject (the one with the Animator and the vp_FPBodyAnimator components on it. Then go to the Unity top / main menu and click "Window" -> "Animator" (not to be confused with "动画(Animation)").

Full body animations

There are examples of full body animations in the demos, e.g. the "OutOfControl" and "Climb" states. These cases are solved simply by playing the same animation in the upper and lower body layers at the same time. Theoretically, you could also play a full body animation either by having it in the base layer and disabling the two other layers or by disabling the UFPS body animator script altogether and assigning another one, maybe even assigning a different animator controller. Everything is possible. One thing is for sure, though: animation is tricky territory and you will want to know Mecanim and Mecanim scripting well.

State machines

Lower Body

Upper Body (main)

Upper Body -> Firearm

Upper Body -> Unarmed

There is a special case in this state machine when it comes to running vs. crouching, where control is allowed to pass from Crouch to Run even if 'IsRunning' is false. This is necessary or control will always pass via walk due to the activation order of the events.

Upper Body -> Melee Weapon

Note that melee combat has very limited support in the first version of the body system and the melee state machine and animation are placeholders.

Parameters of the UFPSExampleAnimator

Floating point values

Parameter

UFPS source

Mecanim destination

Forward

Player.Velocity

Lower Body -> forward / backward leg animation

Pitch

Player.Rotation

Upper Body -> FireArm -> up / down aim animation

Strafe

Player.InputMoveVector & Crouch, vp_BodyAnimator yaw logic

Lower Body -> sideways (strafing) leg animation

Turn

vp_BodyAnimator yaw logic

Lower Body -> idle turn animation

VerticalMove

Player.MotorThrottle.y (jump input)

Lower Body -> jump animation

Booleans

Parameter

UFPS source

Mecanim destination

IsAttacking

Player.Attack.active

Upper Body -> Firearm & Melee -> attack / zoom animation

IsClimbing

Player.Climb.active

All statemachines -> climb trigger

IsCrouching

Player.Crouch.active

Lower Body -> crouch animation, Upper Body -> CrouchAttackZoom

IsGrounded

vp_FPController.Grounded (vp_FPBodyAnimator)

Lower Body -> most states, Upper Body -> Unarmed -> most states

UpdateGrounded (vp_BodyAnimator)

IsMoving

Player.MotorThrottle (vp_FPBodyAnimator)

Lower Body -> most states, Upper Body -> Unarmed -> most states, Upper Body -> Melee -> most states

Player.Velocity (vp_BodyAnimator)

IsOutOfControl

Player.OutOfControl.active

All statemachines -> out of control trigger

IsReloading

Player.Reload.active

Upper Body -> Firearm -> reload trigger

IsRunning

Player.Run + Player.MotorThrottle (vp_FPBodyAnimator)

Player.Run + Player.Velocity (vp_BodyAnimator)

Lower Body -> most states, Upper Body -> Unarmed -> most states, Upper Body -> Melee -> most states

IsSettingWeapon

Player.SetWeapon.active

Upper Body (main) -> setweapon state

IsZooming

Player.Zoom.active

Upper Body -> Firearm -> attack / zoom animation

Triggers

Parameter

UFPS source

Mecanim destination

StartClimb

Player.Climb (OnStart_)

All statemachines -> climb state

StartOutOfControl

Player.OutOfControl (OnStart_)

All statemachines -> outofcontrol state

StartReload

Player.Reload (OnStart_)

Upper Body -> Firearm -> reload state

Integers (enum indices)

Parameter

UFPS source

Mecanim destination

WeaponGripIndex

Player.CurrentWeaponGrip (vp_Weapon)

Upper Body (main) setweapon state

WeaponTypeIndex

Player.CurrentWeaponType (vp_Weapon)

Upper Body (main) setweapon state

Supported animation content

DISCLAIMER: Regarding the included animation library: UFPS contains a folder with animations which are provided for prototyping, demonstration and testing purposes only.

Most animations come from various free examples by UnityTechnologies. Others have been slapped together in 5 minutes for quick tests. Some of the animations may drop lots of warnings, some may not work as expected, and some may not suite every character rig.

In truth we can not provide support for these animation clips in any meaningful way. They are to be seen as demo content only. For your actual game we strongly recommend obtaining a more comprehensive and higher quality animation library.

Body scripting

The default UFPS player setup is certainly moddable, but the better you know Mecanim, C# scripting and UFPS specific scripting concepts (in that order), the better your chances will be of implementing your own game design. This chapter collects some lore and good-to-know bits for scripters about the UFPS player body systems.

Terminology

Local player

The single in-world player object that is controlled by the human operating this physical machine. A local player can exist in two render modes: 1st and 3rd person.

Remote player

Any in-world player object that is not controlled by the human who operates the local computer. Can be controlled by a human or AI, but never performs rendering (has no camera) and never has a physical input device connected to the local machine.

  1. In multiplayer: the local representation of a player that is actually playing from another machine
  2. This term is sometimes (sloppily) used in reference to an AI controlled player / bot, especially if that player has been created using the 'Generate Remote Player' wizard.

Look Point

On a local player
On a remote player

Look Direction

In Local 1st person
In Local 3rd person / Remote players

IsFirstPerson

This property is used all over the place and reports the 1st/3rd person status of the player. The property will return:

... and may be accessed using the player event handler 'IsFirstPerson' value event, e.g:

        if(Player.IsFirstPerson.Get())

Recommended components and scripts to study

Please investigate the editor inspector and code comments of the following scripts for more insight:

Where to find the 3rd person code?

This code is part of the first person camera class due to the intimate relations of different aspects of camera logic in the two modes. The mode is disabled by default and should incur zero overhead in a first-person-only setup. To enable the mode, set 'Position3rdPersonOffset' in the camera's 'Position Springs' foldout to a non-Vector3.zero value and fire the new 'CameraToggle3rdPerson' message with the player event handler (or just press "V" in DemoScene3).

Why is the bullet always fired from middle of camera in 1st person?

Because of the weapon camera. Sometimes the barrel will appear to be in front of a wall when in fact it's sticking through it. Bullets must be fired from the camera in order to end up where the barrel points on the wall.

What exactly does the ragdoll handler do?

The ragdoll handler scans the player hierarchy on startup to store any (pre-existing) ragdoll joints, rigidbodies and colliders for later quick-toggling on / off. The initial state of all the objects are also stored for respawning purposes. The ragdoll handler then starts listening for the player's death event and, upon death, disables the body animator and activates any ragdoll components. Finally the character controller's world velocity is carried over into the ragdoll rigidbodies. When the player respawns, its ragdoll joints and colliders are returned to their default states and disabled. Control is then given back to the player's body animator.

In case of funky headlook

If headlook "gets weird" somehow, if the head tilts to the shoulder or looks in the wrong direction, this can be a somewhat complicated scripting issue. From a spine-initialization perspective, there is a big difference between starting the game with a character that already exists in the scene, versus one that is instantiated by script at runtime. If you start experiencing this:

NOTE: vp_BodyAnimator's "HeadPoint" rotation can not be set every frame - it should be manipulated as rarely as possible even if it must always point in the correct direction.

Using the "Generate Remote Player" wizard for AI and multiplayer

It is important to note that the main local player prefab has many scripts with the prefix "vp_FP" and these scripts should never be used on remote or AI players because they assume access to camera and keyboard / mouse input. Luckily, the most important player scripts also exist in a base version simply prefixed "vp_" and these scripts can normally be used on non-local player objects.

The 'Generate Remote Player' wizard strips a 1st person player of all scripts that assume camera & input, and in many cases converts the "vp_FP" scripts to their "vp_" equivalents. The resulting gameobject could then be spawned in multiplayer to represent a player of the same type as the local player, or you could design AI enemies using the 1st person player workflow (beginning by making sure they handle and animate well) and convert them into AI foes using the wizard as the second stage in the process.

The wizard is run by selecting the root object of a local player prefab (for example, the "Hero" in DemoScene3) and going to the top main menu: "UFPS -> Wizards -> Generate Remote Player". This will create a stripped down, "remoteplayer-legal" version of the player. This object won't do anything in and of itself. It is just intended as a starting point for adding AI or multiplayer features (in our own upcoming multiplayer adaptation we actually use this raw wizard output exactly as-is and apply any additional components needed for multiplayer at runtime). Of course, you may not want to use all the components retained on the player by the wizard. In this case you can mod the wizard or remove them manually.

For AI, the UFPS event system can be manipulated quite easily. Just add a vp_PlayerEventHandler (without the "FP") script to the player and add custom scripts to interact with it. Note that the wizard doesn't produce a controller or collider - nor movement support - which means you will have to add those and rotate and move the object using your own logic. Other than that it has all the weapons and shooters needed already, and you just need to toggle the 3rd person weapon objects on and off in their hands, make them look at something and send the events that fire the weapons.

It should be noted that all of the local player scripts do incur quite an overhead and are not suitable for spawning legions of furious AI. In the case of a village full of NPCs that just need to stand still and turn towards the player and activate dialogs etc. it would probably be better to make new scripts (or new versions of the included ones) that don't require a player event handler.

Body Troubleshooting

Body related issues

The player model doesn't stick to the center of the charactercontroller, but rotates around it in a huge arc /

The player model walks away from the charactercontroller

My ragdoll keeps falling over backwards, but I want it to fall over forwards

My remote player or 3rd person player starts swiveling around its hip like crazy

My character is invisible and won't move. Upon closer inspection its body floats far away in the air and wobbles about strangely

Verify that the bodyanimator component of the character does not have headlook nodes set to nodes in another model.

The camera shakes violently when I move

The camera collision feature casts a ray to intersect with walls. There may be an active collider on the body (ragdoll or player damage collider) that does not have the correct layer.

The local player starts stopping, stuttering or jumping erratically high up in the air for no apparent reason, especially when moving

Headlook is weird somehow: head tilts to / rests on shoulder or looks in wrong direction

See this note in the body scripting chapter.

Weapon related issues

I have assigned a 3rd person weapon to the hand bone of my character and positioned it correctly but it won't appear in-game

Make sure that you have also assigned the model to the '3rdPersonWeaponModel' slot of the corresponding vp_FPWeapon component (the weapon childed directly under the camera)

When I aim or shoot in 3rd person, the hand of my character points in a wrong / unnatural direction

You must calibrate the aim of the weapon. To do so, please see the weapon aim tutorial.

When I calibrate weapon aim, the next time I start the game it's broken

Always make sure that all 3rd person weapons are activated on the character before starting the game or calibrating weapon aim (basically the character should have a big bundle of guns in its right hand). Otherwise, the "virgin" relative rotations of the weapons inside the hand will not be initialized correctly on startup and weapon aim will break. This is not ideal workflow and something we are planning to fix down the line.

I am building a new player based on an old player prefab. The old weapons are hovering in front of me even though i have removed them from the FPcamera

You must delete the old 3rd person weapons childed to the right hand bone of the player body too.

Firearm shells fly off at an extremely high forward or sideways velocity when I'm moving and shooting

Make sure that your player's main object (with the collider) is set to layer: localplayer, otherwise shells may collide with the player when it is moving.

预设(Presets)

The Preset system allows you to take a snapshot of all the settings in a component and save it to a text file. Presets can be loaded via script at runtime and used to quickly manipulate all the parameters of a component as needed by the gameplay. You'll find the "Preset" foldout at the bottom of most components in the inspector.

Load & Save

These buttons will open a file dialog allowing you to load or save presets to disk. Saving a preset will result in all the current parameter values of the component being dumped to disk. Loading a preset will alter the current component values with data from the preset. Preset text files are meant to be assigned to player states under the State foldout (see the 状态(States) chapter).

IMPORTANT: Assets (such as 3d objects and sounds) can not be loaded or saved via text presets. This is because the Unity Editor AssetDatabase is no longer accessible once the game has been built. Inspector slots for sound, 3d meshes and textures always have to be set manually in the Inspector or via scripting methods.

Save Tweaks

This feature will save partial presets, that is: create or update a preset with only the values modified since the last time you pressed Play or changed the states at runtime. The purpose of this will usually be to create presets for use with the State Manager.

For example: the player may pick up a powerup that should only affect running speed. To create a preset for this, you could select the FPController component in the Inspector, start the game, alter the "MotorAcceleration" parameter and press "Save Tweaks". This would result in a FPController preset with only the acceleration parameter in it. See the 状态(States) chapter to learn how to assign such a partial preset to a player state and bind it to a button.

状态(States)

Any fast-paced FPS will have the player switching between different modifier keys quickly and repeatedly (e.g. crouching, zooming, running). This calls for swapping lots of presets at runtime, usually requiring lots of scripting, for all the special cases and key combos. The UFPS State Manager simplifies this by moving much of the work into the Editor and solving runtime preset blending automagically. It will combine multiple presets smoothly, depending on a current combination of 状态(States).

States are completely optional to use. If you don't need them, don't add any states and your component will simply use the currect Inspector settings as its Default and only state.

States can be used not only for input, but for messing with the player in many different ways. For instance, you could use timers to activate a "ShellShock" state shaking the camera for a limited amount of time, or you could use triggers to prevent the player from enabling a certain state in a certain area.

Creating a new state

  1. Select an FPS component in the hierarchy (for example the FPCamera).
  2. Expand the "State" foldout.
  3. Press the "Add State" button . A new empty state will appear.
  4. Name the state by clicking and typing a name into the "New State" box. Remember that names are case sensitive.
  5. Drag a preset text asset from the Project View into the "None (TextAsset)" box (the default text presets are located in the "Presets" folder in the UFPS root).
  6. Done. You now have a new state with a preset assigned to it. It won't do anything yet, though. The state needs to be activated via script.

Activating and deactivating states

Here's an example of toggling a state on and off via script.


if (Input.GetKeyDown(KeyCode.H))

SetState("MyState", true);

if (Input.GetKeyUp(KeyCode.H))

SetState("MyState", false);

There are many other ways of using states. Study the vp_FPWeaponHandler script to get more acquainted with some different methods of working with states and timers.

State order

The state system works basically like the layers of a paint program. The state (layer) at the bottom represents the current inspector values of a component. The state above it represents a preset that will override all - or just some - of the underlying one's values, and so on up the list. If a state is disabled, the remaining presets in the list will be smoothly recombined (let's say you release the Crouch key while still holding the Zoom key).

To bump up a state, press the little arrow button  at the right and the state will jump up one step. Any currently active states in the top will override any currently active states below them.

The Default state

The bottommost state is called the 'Default' state. It represents the standard mode of the component and cannot be removed or renamed. It should usually be left empty: "None (TextAsset)", in which case it uses the current Inspector settings for the component. If you do choose to assign a text preset to the Default state, it will lock down the component, preventing editing. If so the component can be modified at runtime only, and changes will revert when the app stops (presets can still be saved though). To re-enable editing, the 'Default' state must be unlocked by pressing the small 'Unlock' button .

State blocking

Sometimes you want states to override each other entirely. For example, you may not want the player to be able to aim down sights while sprinting, and so you want the Run state to override the Zoom state on the camera and weapon. Theoretically, you can block out all underlying states by applying a preset that contains every possible value for the component in question. However, this approach soon becomes labor intensive.

Instead, use state blocking. This function lets a state "mute" one or more other states on the component while active. Press the little  button to unfold a list of available states to block. Every state that is ticked will be blocked out while this state is active. States that block other states always have a blue  button. Also, while the blocking foldout is open, any affected states are highlighted in blue in the regular state list.

States can not block themselves, states that block them, or the Default state.

Deleting a state

To delete a state, simply press the small  button at the far right. Beware though; deleting a state can not be undone!

Removing a preset

To remove a preset from a state, press the small circle icon  to open a "Select TextAsset" window. At the top of the list, select "None".

Persist play mode changes

The Default state can optionally be "persisted", meaning the variables you change during play will not be reset when the application stops. Whenever this checkbox is unchecked and the app is stopped, Unity will reset the Default state to what it was before you pressed play (the default Unity behaviour). If it's checked, Unity will stay away from your variables. Please note that only the currently selected component will be persisted even if the checkbox is checked on several components.

抛射体 子弹(Projectiles)

UFPS uses classic hitscan bullets. This means that the game uses instant raycasting rather than Newtonian physics to move the bullet. This is the way in which bullets traditionally work in first person shooter games.

Please note that the way bullets are constructed has significantly changed in UFPS 1.6 versus previous versions. Previously, a bullet would contain a decal mesh, audio source and renderer with a generic bullet hole texture. The new bullets have no rendering capabilities. Instead they leave decal spawning to the SurfaceEffect system, which allows spawning different decals depending on the surface hit. The bullets still play an impact sound however

.

Anatomy of a bullet prefab

  1. A vp_FXBullet script
  2. An audio source

This prefab goes into the player's vp_FPWeaponShooter script, on e.g. the "Machinegun".

Anatomy of a bullet hole decal prefab

  1. A MeshFilter
  2. A MeshRenderer with a classic 2-triangle quad (its normal aligned with the Z-vector). The overlap detection features of vp_DecalManager require this type of decal (!).

This prefab goes into the 'Decal' section of a SurfaceEffect, e.g. "BulletOnWood".

Creating a new bullet type

  1. Duplicate one of the existing projectile prefabs under 'Content/Prefabs/Projectiles', for example: PistolBullet
  2. Rename it to something good
  3. Create a new impact event and assign it to the 'Impact Event' slot of your new projectile prefab
  4. In the project view, select the Default surface type (Content/Surfaces/SurfaceTypes/Default)
  5. Increase the 'Size' of the Default surface type by one

IMPORTANT: Be very careful not to write a lower number than the currently existing one, or the the last elements in the list will be destroyed.

  1. In the bottom-most element that was created, assign the new ImpactEvent you created
  2. Assign an existing default surface effect in the 'Surface Effect' below, or create a new one.

TIP: Just to make sure your new projectile type works, you can temporarily assign the 'BulletOnFlesh' effect, which will make your projectile spawn blood on whatever it hits.

  1. Now, make sure to add your new impact type to all the surface types in the same way
  2. Select the vp_FPWeaponShooter component that you want to shoot this projectile, and in the Inspector, open the 'Projectile' foldout and assign the projectile prefab. also you may want to adjust the Scale of the prefab when it spawns.

Disabling quad raycasts per-projectile

To disable quad raycast for a projectile, set 'Allow Edge Overlap' to the maximum of 0.5. The DecalManager uses quadruple raycasts to check for good or bad decal placement. But on really small projectiles, such as a shotgun pellets, it's really performance overkill to use this feature.

Making bullets ignore triggers

to prevent a trigger from interfering with bullets, put it in the 'Trigger' layer (default: 27). This will make bullets fly right through triggers.

on a scripting.

You probably don't want to disregard a hit based on !collider.isTrigger, because that would make bullets _disappear_ if they hit a trigger.

Spawning certain impact effects such as blood on enemies

  1. Create a new surface effect (for example: OrcBlood) and make sure it has blood effects (no decals)
  2. Create a new surface type (for example: OrcFlesh). assign all the impact types that should be able to spawn the blood effect, and bind them to your new surface effect.
  3. Add a vp_SurfaceIdentifier component to the the enemy collider and assign the surface type

Preventing decals from attaching to enemies

  1. Assign a vp_SurfaceIdentifier to the enemy collider.
  2. Make sure "Allow Decals" of the SurfaceIdentifier is OFF.

To prevent decals from attaching to enemies when fallbacks get activated, it is usually a good idea to configure the SurfaceManager to have Default Fallbacks -> Allow Decals -> OFF.

枪炮口的闪光(Muzzle Flash)es

vp_MuzzleFlash handles logic for showing an additive, randomly rotated muzzle flash in front of the weapon. The script should be attached to a gameobject with a mesh to be used as the muzzle flash, using the "Particles/Additive shader".

This gameobject will always be enabled but most often invisible. When a shot is fired, it  snaps to a new random rotation and its alpha is set to full. It then immediately fades out.


Creating a MuzzleFlash prefab from scratch

  1. Create a muzzle flash texture with and alpha channel, to be used with the "Particles/Additive" shader.
  2. Create a mesh for the muzzle flash in your favorite 3d package, facing along the Z vector.
  3. In Unity, create an empty gameobject and name it something.
  4. Drag your mesh onto the gameobject. Make sure its import scale and orientation is correct. Also, make sure that the muzzle flash never gets a collider component, or it will mess with your character controller's motion.
  5. Drag the vp_MuzzleFlash script onto the gameobject.
  6. Set the shader of your object to "Particles/Additive".

TIP: Sometimes the muzzle flash may display briefly (for one frame) right when the game is started. In order to prevent this, set the initial alpha of its material to 0.

  1. When happy, drag your gameobject from the Unity Hierarchy to the Project view in order to create a prefab. Next, this prefab can be dragged onto the "MuzzleFlash > Prefab" field of a vp_FPWeaponShooter component.

弹壳(Shells)

vp_Shell is a script for managing the behavior of shell casings ejected from weapons. It uses managed rigidbody physics to behave in a manner typical of bouncing shell casings. It also plays random bounce sounds. The script should be added to a gameobject with a mesh to be used as the shell casing. The vp_Shooter component which spawned the shell is responsible for setting its initial velocity and random spin.


Creating a Shell prefab from scratch

  1. Create a textured shell mesh in your favorite 3d package, facing along the Z vector. It is recommended to make the shell 1x1 unit large, and using the "Scale" parameter of vp_FPWeaponShooter to scale it (at a later stage).
  2. In Unity, create an empty gameobject and name it something.
  3. Drag your custom mesh onto the gameobject. Make sure its import scale and orientation is correct.
  4. Drag the vp_Shell script onto the gameobject.
  5. Set the following values on the RigidBody of the gameobject:

  6. Adjust the Capsule Collider of the gameobject. Begin by dragging the "Weapons/Shell/Shell.physicMaterial" to the "Material" slot. For the rest of the parameters, the following tested values can be a good start:

  1. Adjust the parameters of the vp_Shell component (see info on the parameters below).
  2. When happy, drag your gameobject from the Unity Hierarchy to the Project view in order to create a prefab. Next, this prefab can be dragged onto the "Shell > Prefab" field of a vp_FPWeaponShooter component.

Parameters

Life Time

Time to live in seconds for this type of shell. When the time has passed, the shell is quickly and discretely shrunk and destroyed.

Persistence

This is the chance of a shell not being removed after settling on the ground. An optional optimization feature for weapons that emit large amounts of shells. A value of 0 means that all shells will be removed after bouncing once or twice. A value of 0.5 means that roughly half of the shells will be removed early. A value of 1 means that all shells will stick around for the remainder of their lifetime.

Bounce Sounds

This is the shell's list of bounce sounds. When a shell hits the ground sufficiently hard, one of these will be randomly selected and played. There is no limit to the amount of sounds. In order to add sounds to an empty list, change the "Size " parameter to the amount of sounds you intend to add, and new slots will appear.

玩家伤害处理(Player Damage Handler)

Please note: This manual chapter reflects UFPS v1.4.6 and is out of date. In UFPS 1.4.7+, damage handlers are not responsible for respawning. Until we've had time to update this chapter, please see the UFPS 1.4.7 releasenotes ("System wide overhauls" section) for up-to-date info on damage handlers and respawners.

vp_PlayerDamageHandler is a helper class to give your scene objects the capability of taking damage, dying and respawning. To use it, just drag it to a gameobject inside your level and tweak its parameters. You should then be able to shoot and kill it.

When the PlayerDamageHandler's "Health" goes below zero, it will call its "Die" method to remove the object, restore health to the original value and respawn after some time in the original location.

Any other script can send damage to the PlayerDamageHandler using the following code:

hitObject.SendMessage("Damage", 1.0f, SendMessageOptions.DontRequireReceiver);

Where "hitObject" is the PlayerDamageHandler's gameobject and "1.0f" is the amount of damage to do.


Parameters

Health

Initial health of the object instance, to be reset on respawn.

DeathEffect

Gameobject to spawn when the object dies. The included examples all use an explosion, but this could also be a gameobject hierarchy with rigidbody rubble, such as the shards of a vase or wood debris from a crate.

MinDeathDelay & MaxDeathDelay

Random timespan in seconds to delay death. Good for designing cool serial explosions!

Respawns

Whether to respawn the object or just delete it upon death.

MinRespawnTime & MaxRespawnTime

Random timespan in seconds to delay respawn. This can be used to make respawning less predictable.

RespawnCheckRadius

Radius around the object that must be cleared of other objects before respawn can take place. If the spawn area is occupied the PlayerDamageHandler will reschedule respawn using a new RespawnTime.

RespawnSound

Sound to play upon respawn.

库存 背包(Inventory)

UFPS has a robust inventory system with simple drag & drop editor workflow, item pickups, item and ammo caps, seamless interaction with the WeaponHandler and capacity limitation by amount, space or weight.

The system separates item type information from player gameobjects, keeping it in a central location which is generally good for game logic. Please note that there is no in-game GUI implementation of the inventory at this point, only gameplay.

If you're in a hurry or looking to solve a specific problem, skip ahead to the case-specific mini tutorials below. If you wish to gain some fundamental knowledge of how things work before you dive in, it is recommended to read the "Basics" chapter first. This should promote some "Aha" moments in no time :)

The files for the old (vp_SimpleInventory) system are still included with UFPS for the time being (although not guaranteed to work 100%). The old docs are available here.

Basics

The first important thing to keep in mind is that the main FPS camera should have every weapon childed to it that the player will ever be able to use. Weapons are never taken away from - or added to - this gameobject hierarchy. They are always there; sometimes hidden, sometimes visible.

The job of the inventory is basically to restrict usage of these predefined weapons. The weapon system asks the inventory for permission before wielding, reloading or firing any weapon.

It is important to understand that the inventory is just a list, or a record-keeper tracking the player's belongings. Game-world objects are not really understood by the inventory and never interact with the inventory directly.

Example: When a player collides with a pistol pickup object, the pistol gameobject does not actually move into the player's backpack. Rather, it transmits a message to the player's backback, saying "I am a dispenser of pistol licenses and you are now certified to enable 1 pistol". It then goes into hiding.

Now, when the player presses the button that wields the pistol, the weapon handler will ask the backpack "are we registered for pistol use?", to which the backpack will proudly reply "YES", and the pistol wield sequence will get a go-ahead.

Finally, there's a lot of talk of weapons and ammo. The inventory system is written for general use and doesn't really care whether a UnitBank is a flame thrower or a Pez dispenser. In other words: there is plenty of room for creativity!

Item Scripts

The inventory system currenty has 3 main components to solve common tasks. For detailed info on their usage, see the tutorial chapters further down.

vp_PIayerInventory

This component is responsible for keeping track of the item types that the player currently has access to, and to reply to other scripts that poll for this information.

vp_ItemIdentifier

The item identifier can be slapped onto any gameobject to basically say: "This is an item of type X". It is what allows the weapon handler to associate a particular first person weapon object with info from the inventory.

vp_ItemPickup

This component can be added to a game object to give the player access to a certain item on collision. It will temporarily hide its gameobject when it triggers (the gameobject can be re-enabled again using a vp_Respawner component).

Item Types

Inventory scripts communicate by referring to 3 types of ScriptableObject, or ItemTypes. Think of these as the id cards for items, explaining what they are and in some cases defining basic inventory related stats. ItemType objects can be created from the top menu: UFPS -> Wizards -> Create Item Type.

Item

This is the base ItemType that declares simple aspects such as the name, icon and description of an object. It is used for items that have no advanced inventory related logic in themselves.

UnitBank

This extended item type describes any object that can be "loaded" with a certain amount of compatible "Units". It is used to describe devices that are powered by a finite resource, for example: pistol, flamethrower, shotgun, crossbow, fire extinguishier, tazer, wand, cell phone, disposable camera, spray can, power drill, chain saw, oxygen mask, syringe.

Unit

Units are what power UnitBanks. In other words, each UnitType represents a limited, portable resource of which the player can potentially carry a large amount (which is why they are implemented as integer counters rather than object instances). Some examples of units would be: bullet, fire extinguishing foam, mana, shell, battery, film, oxygen, gasoline, red spray paint, blue spray paint, sedative, bolt, arrow.

Base UFPS has 6 demo item types, one for every physical object that can be picked up (although a typical finished game could have scores or hundreds). The demo item types are:

Regarding Ammo Clips: There is no "Clips" concept in UFPS. The inventory simply has a bank of Units (bullets) of a certain type and when you reload, units get pulled up to the point where your weapon gets filled (in effect, if you have 17 bullets loaded in a 19 bullet pistol and hit reload, only 2 bullets will be pulled from the inventory instead of a whole clip of 19). This means that the "clip" concept only exists in the form of vp_ItemPickup prefabs that award a number of Units and have names and meshes that happen to resemble ammo clips.

Adding the Inventory

(Note that the AdvancedPlayer example prefab comes with a vp_PIayerInventory component already on it. The below steps only apply if you are using the SimplePlayer or Camera&Controller prefabs - or if you have created a custom player setup.)

  1. First, make sure you have removed any old (vp_SimpleInventory) component from your player gameobject.
  2. Add a vp_PlayerInventory component to your main player gameobject.

From now on, every time the WeaponHandler wants to ready a weapon or fire a bullet, the inventory component will interfere - giving or denying permission. That is: as long as the items involved are identified using ItemType objects.

Enabling a weapon for inventory use

Step 1/2: Declare an ItemType for your weapon

  1. Go to the top menu: UFPS -> Wizards -> Create Item Type
  1. An ItemType object has been created in the "UFPS/Base/Content/ItemTypes" folder. This can be dragged into the Item Records section of the vp_PIayerInventory component to instantly give the player access to this item.

An ItemType object as shown in the Project View and Inspector

An instance of the same ItemType in the form of an inventory Item Record

TIP: Think of this object as the ID CARD of your item. It will be used by all the scripts that handle items (vp_PIayerInventory, vp_ItemIdentifier, vp_ItemPickup) every time they need to communicate about this type of item.

  1. Select and name your item type object in the Project View. Also, fill in the basic info for the new item type. For example: the ammo, or Unit capacity of a weapon is determined here. Click on the small circle beside the item slot to choose from available item types.


If you wish to create a new ammo type for your weapon, also create an ItemType for the ammo in the same way described above, but choose Unit instead of UnitBank.

TIP: The UFPS demo weapons have over-simplified type names for clarity, but in any "real" game (with many types of similar weapons) your ItemType should pinpoint the actual model name of the weapon. Names like "Pistol", "Knife", "MachineGun" or "AssaultRifle" are not very practical. Examples of better names would be "Glock19", "Colt45", "AK47", "KABAR" and "M4", names that allow the inventory system to distinguish between items of similar category.

Step 2/2: Add an Item Identifier to the FPS weapon

Now we have declared that a certain type of item exists, but there is nothing binding that item type to any particular first person weapon yet. Your 3D weapon needs an Item Identifier.

  1. Select your first person weapon gameobject that is childed under the FPSCamera gameobject, and add a vp_ItemIdentifier component to the weapon gameobject.

  1. In the project view, browse to the correct ItemType object and drag it to the big empty slot on the vp_ItemIdentifier component.


... OR click on the small circle on the item slot and choose from all the available item types.

Done! Now whenever your player has an active vp_PIayerInventory component, you will be able to wield this weapon as long as the inventory contains a matching record of the same ItemType object. If not, it means your player does not yet own that weapon.

Creating an Item Pickup

  1. Add a vp_ItemPickup component to the pickup gameobject.

  1. Drag an ItemType object from the "UFPS/Base/Content/ItemTypes" folder to the empty slot on the component.

... OR click on the small circle on the item slot and choose from all the available item types.

  1. If the item is of type UnitBank, set the number of units (bullets) that should accompany this pickup. It might be a half-full machinegun, or an empty one (note that this value will be capped at runtime, by the max capacity of the UnitBank).

Done. Now whenever a player collides with this gameobject, the vp_ItemPickup component will send a message to the player's vp_PIayerInventory component that the player has access to the ItemType.

Setting the Start Weapon

  1. On your player gameobject, locate the vp_FPWeaponHandler component and set its "Start Weapon" variable to the weapon index of your weapon.

"Weapon Index" here refers to the order of your weapon as childed under the FPSCamera gameobject, and has nothing to do with ordering inside the inventory.

  1. Double check that your weapon gameobject has a properly set up vp_ItemIdentifier component. If not, see the "Enable a weapon for inventory use" section above.
  2. With the game stopped (not running) ... on your player gameobject, locate the vp_PIayerInventory component, and open the "Item Records" foldout.
  3. Make sure the list contains a record for the ItemType of your start weapon. If not, add one by either dragging it from the "UFPS/Base/Content/ItemTypes" folder, or by clicking the small circle next to the item slot.

Limiting inventory capacity

The Item Caps and Space Limit foldouts of the vp_PIayerInventory component has settings to limit item access by type & amount, and volume or weight. By combining different types of rules you can go very creative with inventory capacity.

Please note: While the inventory supports multiple weapons of the same type, currently the WeaponHandler does not. Future versions of UFPS will address this (things like dual wield, a.k.a. akimbo, involves some heavy re-writing of the weapon handler). For now it is recommended to always use an Item Cap of 1 for all weapons.

Limit specific items by Amount

  1. Locate the vp_PIayerInventory component on your player and open the "Item Caps" foldout
  2. Make sure the "Enabled" checkbox is checked
  3. Populate the list with the item types you would like limited.

If you would like the player to be restricted to carrying only the items in the list - check the "Allow only listed types" checkbox.

Limit items by Volume or Weight

  1. Locate the vp_PIayerInventory component on your player gameobject
  2. Open the "Space Limit" foldout and make sure the "Enabled" checkbox is checked
  3. Decide whether your player should be limited in capacity by weight or by volume. Also, make up your mind on a suitable metric. This is what "Space" will effectively mean and could be cubic inches, cubic feet, or kilograms, pounds etc ... you decide.
  4. Fill in the total capacity for the player in weight or volume. The blue meter will indicate how encumbered your player is. When it reaches 100%, it will no longer be able to pick up objects.
  5. On every ItemType object in your game (located at "UFPS/Base/Content/ItemTypes") set the "Space" parameter to a fitting amount in your chosen volume or weight metric.

TIP: If you would like certain items to not be affected by Space rules, just leave their Space at zero (0).

Unlimited items and ammo

Setting zero item restrictions

  1. Locate the vp_PIayerInventory component on the player gameobject.
  2. Unfold the "Item Caps" foldout and uncheck the "Enabled" checkbox.

Note that while this will allow you to pick up unlimited items and ammo, it will not affect the capacity of your weapons (loaded ammo will still be limited).

Setting unlimited ammo & items

To play the game with unlimited ammo and items, simply disable (or remove) the vp_PIayerInventory component.

Item ID

Item ID is a scripting feature that provides a way to associate a certain gameobject with a specific item record. This is useful in games with quests or puzzles.

The inventory system does no hard-coded assignment of item values: if you add five pistols via the inspector they will all have an ID of zero, although the pickup system can optionally assign an inspector-defined ID upon pickup.

The UFPS demo items all have the default ID of 0, but your own game code can be written to rely heavily on IDs. Perhaps your game has hundreds of item instances and you need your ID:s to be GUID:s (globally unique identifiers), or you may be building an MMO where item IDs get pulled from a remote database. It's up to you as a programmer.

TIP: The vp_ItemInstance class has a method, SetUniqueID, which will assign a positive integer value that is practically guaranteed to be unique.

Item Identifier ID logic

There is some lore to how the inventory will pinpoint which item record to interact with given an incoming ID-based item request. That is: when a weapon is fired or reloaded and you want this to affect a specific item record in the inventory by setting the weapon's vp_ItemIdentifier ID to a positive value.

The only way to target a specific inventory item is to make sure the item pickup / item record has a unique, positive ID, and the item identifier has the exact same ID. If the inventory has multiple items with the same ID, the first item will get picked.

When using a zero ID, you are basically saying "I don't care about the ID. Let the inventory decide". In this case the inventory will always choose the first item record of matching type, even if the first item record has a positive ID, and there are item records further down the list with zero IDs.

if item identifier ID is zero

inventory always selects first item record of matching type (regardless of ID)

aborts if there is no item record of matching type

if item identifier ID is positive

inventory selects the first item record of matching type and ID (if any)

aborts if there is no item record of matching type and ID

if item identifier ID is positive and inventory item record IDs are all zero

always aborts

爆炸(Explosions)

vp_Explosion is a simple death effect for exploding objects. It will apply damage and a physical force to all rigidbodies and player event handlers within range. It will also play a sound and spawn a list of FX gameobjects. These would typically be particles, but could also contain things like image effects. The explosion gameobject destroys itself as soon as the sound has stopped playing.


Spawning an Explosion from script

The included explosion prefab is intended as an example death effect for the vp_PlayerDamageHandler, but you can also spawn an explosion from script very easily with the following lines of code:

Object.Instantiate(ExplosionPrefab, position, Quaternion.identity);

Where "position" is the desired vector3 location of your blast, and "ExplosionPrefab" is a GameObject declared as public variable at the top of your script and assigned in the Editor:

public GameObject ExplosionPrefab = null;

Parameters

Radius

Any objects within this radius in meters will be affected by the explosion.

Force

Amount of motion force to apply to affected objects. Force will wear off with distance.

UpForce

How much to push affected objects up into the air. This will only take effect on objects that are currently grounded.

Damage

Amount of damage to apply to objects via their "Damage" method. Damage will wear off with distance.

CameraShake

How much of a shockwave impulse to apply to the camera. The impulse will wear off with distance.

DamageMethodName

User defined name of the damage method on the affected object.

TIP: By using different damage method names for different prefabs (and creating corresponding methods in your target object scripts) multiple damage types can be supported. For instance: !MagicDamage", "FreezingDamage", "PlasmaDamage" etc.

SoundMinPitch & SoundMaxPitch

Random pitch range for the explosion sound. This will add variation and a little realism. Variations in pitch should be kept minimal. A typical Min-Max range would be 0.95-1.05.

FXPrefabs

This is a list of special effects objects to spawn when the explosion goes off. This would typically be particle effects but may also contain rigidbody rubble or wreckages. There is no limit to the amount of objects. In order to add objects to an empty list, change the "Size " parameter to the amount of objects you intend to add, and the corresponding number of fields will appear.


运动平台(Moving Platforms)

Animated level geometry can occur in many shapes. Elevators, revolving doors, train carts, traps, collapsing ceilings and so on. These are commonly referred to as moving platforms; objects that the player can ride on top of - or get pushed around by.

General requirements

The vp_FPController will be moved correctly if standing on top of moving objects (including rigidbodies) that have the MovingPlatform layer and a collider. As long as these two requirements are in place, the player will correctly inherit the rotation and velocity of the object, also when falling or jumping away from it. Sliding will automatically work on tilted or rotated moving objects.

IMPORTANT: In the default UFPS project, "MovingPlatform" is layer number 28. In case you have created a new blank project this may not be the case. Make sure your "MovingPlatform" layer is #28 in the list and it should work. Alternatively you may change the layer number in the file "vp_Layer.cs".

When it comes to moving stuff around in Unity, you really have tons of options! You could easily create your own script to move an object. You could use rigidbodies or use third party tweening libraries. But note that UFPS works best with its own platform script called vp_MovingPlatform. Especially if you experience camera jittering, then it is recommended to try and use this script instead.

Assigning the MovingPlatform layer

  1. Select your platform object and make sure it has a collider.
  2. At the top right of the editor window, click the Layer dropdown and assign the MovingPlatform layer.

You don't have to perform this step if using the vp_MovingPlatform script, in which case the layer will be set at runtime.

Moving platform tutorial

This tutorial explains how to work with the vp_MovingPlatform component. This is a very versatile moving platform class, supporting various motion interpolation modes, path behaviors, collision detection, player physics responses and sound fx. For an in-depth reference of the component, see the next section.

  1. Place an object in your scene. This could be a door, an elevator or anything that should be rideable.
  2. Make sure the object has a Collider component.
  3. In the Hierachy, right click on the object to make one or more duplicates of your platform object.


  1. Rotate and place the duplicates around the map in exactly the places you will want the platform to visit.
  2. Waypoints will be visited in alphabetical order, so preferably rename them using number prefixes.
  3. Drag all the waypoint objects into an empty gameobject and name it something fitting, for example PlatformPath (make sure this object sits in the Hierarchy root).


  1. Select your main platform object (make sure it's outside of the path group) and add a vp_MovingPlatform component to it.
  2. Open the vp_MovingPlatform's Path foldout and drag your waypoint group object into the Waypoints slot.

IMPORTANT: The vp_MovingPlatform script needs to run after the default execution order. Should you experience any issues with it please go to "Edit > Project Settings > Script Execution Order" in the editor, press the litte "+" button, choose "vp_MovingPlatform.cs" and drag it to after the "Default Time".

IMPORTANT: Make sure your waypoints have no active components (especially not colliders) on them - or click the "Generate Gizmos" button (optional). This will attempt to strip all objects in the waypoints group of any and all components and convert them to gizmos that are visible in the editor only.


A platform and two waypoints after clicking "Generate Gizmos"

Path

The Path foldout manages how this platform will negotiate its route.

Type

PingPong

In PingPong mode, the platform will go to the last waypoint via all waypoints - then back the same way.

Loop

In Loop mode, the platform will continuously move through all the waypoints without changing direction.

Target

In Target Mode, the platform will initially stand still, but go to a target waypoint when the player stands on it. This mode enables a number of additional parameters (see below).

Waypoints

This slot should contain a gameobject with waypoint children. See the Moving platform tutorial for more info on how this works.

Auto Start Target

(Target mode only) Determines which waypoint to move to upon player contact.

When Auto Start Target is OFF (0), the platform must be operated via the script's public GoTo method. In case you have no desire to script elevator buttons yourself, see the 交互(Interaction) chapter and the Platform Switch Interactable for more info.

Return Delay

(Target mode only) Determines how long the platform will wait at the destination waypoint before going back to the start.

Cooldown

(Target mode only) This is a value in seconds determining how long the platform will remain shut off after reaching its destination. During this time the player can't activate the platform.

Direction

Decides which direction the platform should initially negotiate its list of waypoints - backwards or forwards.

Movement

The Movement foldout handles the realtime motion pattern of the platform.

Interpolation Mode

EaseInOut

In this mode the platform will accelerate slowly from standing still, reach its top speed, then start decelerating as it approaches its final waypoint, finally gently coming to rest.

EaseIn

In this mode the platform will accelerate slowly from standing still, reach its top speed and stop abrubtly when reaching its final waypoint.

EaseOut

In this mode the platform will almost instantly reach its top speed, then start decelerating as it approaches its final waypoint, coming gently to rest.

EaseOut2

This is a more exaggerated EaseOut. The platform will start very abruptly but take a long time to decelerate and come to rest.

Slerp

This mode will have the platform negotiate waypoints in a rounded pattern. Though sometimes unpredictable, it's fun to play with since it gives the path a slightly organic feel (more so with several waypoints).

Lerp

This is the most basic mode. It will have the platform moving between waypoints with no change in speed, that is: no acceleration or deceleration. This is great for slow moving platforms where you want exact control of the speed, however a platform with many waypoints will have a somewhat robotic feel at higher speeds.

速度(Speed)

A factor determining the overall velocity of the platform.

Rotation

The Rotation foldout handles the realtime rotation pattern of the platform.

Interpolation mode

SyncToMovement

In this mode the platform's angle will interpolate in perfect sync with its position.

EaseOut

In this mode the platform will start rotating abruptly (immediately reaching its top rotation speed), then start decelerating as it approaches the final waypoint, gently coming to rest.

CustomEaseOut

This is a more spring-like version of EaseOut, where you can use the Ease Speed slider to tweak the damping behavior. Values below 0.5 work best.

CustomRotate

This mode lets you specify a constant rotation around an arbitrary vector. This is useful for making platformer puzzles, such as having giant rotating cog wheels in a factory.

Physics

Push Force

This parameter determines how hard to smack the player when it gets run over by the platform. This is useful for moving or rotating doors.

This component works best when the player's vp_FPController component has its collision trigger active. Without a trigger, the controller will still be able to ride on moving platforms, but the platforms will not auto-start when stood upon and will not be able to push the player around or use its intersection solver. See the Controller chapter for more info.

Snap player to top

In the event that the physics engine fails to detect a player collision for some reason, the player may end up inside a moving object. This doesn't look very good. If snap is enabled, the player will in this case be forced to the top of the platform in a single frame, hopefully saving the day.

声音(Sound)

Start

(Target mode only) This sound effect will be played once when a targeting platform starts moving.

Move

This sound will be looped while the platform is moving and will stop when it is not.

Waypoint

This sound will be played whenever the platform hits a waypoint. Great for clunky machinery and the Lerp movement mode.

Stop

(Target mode only) This sound effect will be played once when a targeting platform stops moving.

交互(Interaction)

The Interact Manager component allows interaction with any object that has a vp_Interact component added to it either by using a key for interaction (“F” by default) or by triggering the interactable by touching it with the player, such as a floor switch. There are 4 vp_Interact components: vp_Climb, vp_Grab, vp_Switch and vp_PlatformSwitch.

If you’d like to use the FPInteractManager with other scripts, you can access it via the vp_Activity Interact. So to try and start interaction from the vp_FPInput script, Player.Interact.TryStart() is used. The current interactable is stored in a vp_Value Interactable.

To learn more about vp_Activity, vp_Value and other events, check out the 事件系统(Event system) chapter.

Adding the Interact Manager

  1. Find the Player in the hierarchy (has the vp_FPController component on it).
  2. In the project view search box, type vp_fp.
  3. Drag the vp_FPInteractManager onto the player gameobject.

Parameters

Interact Distance

This is the max distance from the player camera to any object with a vp_Interactable component on it. (Can be overridden by any vp_Interactable).

Max Interact Distance

Every vp_Interactable can override the FPInteractManager’s Interact Distance. This options allows a maximum interact distance to be set. For instance, if a vp_Grab component has an interact distance of 30, but the FPInteractManager’s Max Interact Distance is set to 25 and the player is 26 meters from the grabbable object, the player cannot grab the object until the player is 25 meters or less.

Interactables

A typical interactable will be setup with a C# script that inherits from the vp_Interactable script. Interactables allow the FPInteractManager to communicate with the Interactable. All interactables require a collider. UFPS ships with 4 interactables which can be found by searching the project for the "Interactables" folder. You can of course extend the vp_Interactable class to add more interaction functionality if you like.

Parameters

Interact Type

There are 3 types Normal, Trigger and CollisionTrigger.

Normal

These require the Interact key to be used (“F” by default) and the crosshairs must be looking at the interactable.

Trigger

These types of interactables require the player to come into contact with the object. This also turns on the IsTrigger option on the collider.

CollisionTrigger

These types of interactables require the player to come into contact with the object and keeps collision with the collider intact.

Recipient Tags

By supplying a list of tags, only objects with these tags can interact with an interactable object. If left at 0, the player will be added by default. This is useful if you have a trigger interactable that you want other objects to be able to interact with, such as a floor switch that can be triggered by throwing objects on the switch.

Interact Distance

This setting will override the setting that is on the FPInteractManager. This value also will get overriden by FPInteractManager’s Max Interact Distance. If set to 0, this setting is ignored.

Interact Crosshair

Adding a texture to this setting will change the crosshair to the texture you’ve added when interaction can occur with the interactable (in range and looking at the interactable).

Interact Text

If a string is provided here, the text will be shown on the screen above the crosshair after the Delay Showing Text time.

Delay Showing Text

If this interactable is looked at and in range for the amount of time (in seconds) set here, the Interact Text will be shown.

Climb Interactable

This interactable allows the player to climb objects. Since this interactable uses the object's world forward vector, a little setup is required for this interactable to be effective.

Climb Object Setup

  1. A good setup for Climbing Interactables is to have the climbable object as a child of the actual object. In the screenshots, the Climbable GameObject has the vp_Climb component on it and the collider. The LadderAngled GameObject is the actual ladder with the MeshRender on it. This allows for more flexibility and the climbable can be rotated with the forward vector facing towards the player (The blue Z-Axis arrow).
  2. Make sure that the climbable object (with the vp_Climb script and collider on it) has the IgnoreRaycast layer, or you may get issues with the player falling off the ladder when reaching the top.

IMPORTANT: If you scale the GameObject that has the vp_Climb component on it, you may encounter inconsistencies. Try to keep the scale for the GameObject to Vector3(1,1,1) and change the scale on the collider component instead. An easy way of scaling the collider is in the scene view, if you hold down shift, handles will appear on the collider which you can grab and rescale the collider with.

For interacting with climbable objects without requiring an input key press and with collision still intact, be sure to set the Interact Type to CollisionTrigger.

Parameters

 

Minimum Climb Speed

The player can climb no slower than the speed set here.

Climb Speed

The speed at which the player climbs this object.

Mount Speed

The speed at which the player will grab on and start climbing this object.

Distance To Climbable

During climbing, this will be the distance from the climbable object that the player will stay.

Min Velocity To Climb

This determines what the minimum velocity the player needs to be moving in order to interact with this climbable.

Climb Again Timeout

The amount of time in seconds that must pass once climbing has stopped in order to interact with this climbable again.

Mount Auto Rotate Pitch

Turning this option on will rotate the camera to be level with the horizon when the player mounts this object.

Simple Climb

With this option on, climbing input is handled with “W” moving the player up and “S” moving the player down. If this option is disabled, movement is handled in a more complex manner and works with look direction (pitch only). Here are some examples:

Dismount Force

The amount of force applied when the player dismounts this object (reaches top or bottom of the climbable or jumps off).

声音(Sound)s

Audio Source

The audio source that will play the climbing sounds. If none is provided, defaults to the Audio Source on the player.

Mount Sounds

A list of sounds to be played at random when the player mounts this object.

Dismount Sounds

A list of sounds to be played at random when the player dismounts this object.

Climbing Sound Speed

The speed at which Sounds > Climbing sounds is played

Climbing Pitch

This parameter optionally pitches the grab, drop and throw sounds. Variations in pitch should be kept minimal. "X" is "Min" and "Y" is "Max". A typical Min-Max range would be 0.95-1.05.

Climbing Sounds

A list of sounds to be played at random when the player is climbing this object.

Grab Interactable

This interactable will allow the player to pick up, drop and throw objects. Similar to weapons, it has sophisticated logic to animate the object procedurally while carried. Also, it has functions to handle various physics and collision cases. To setup a Grab interactable, just drag the vp_Grab script onto any object.

Parameters

On Grab Text

This works just like the Interact Text, but will show the text when you pickup an object.

Grab State Crosshair

An optional image to replace the crosshairs while this object is carried. If no image is specified, the crosshairs will just be removed.

Footstep Force

Determines how much the player's footsteps affect the objects motion.

跌落时重心下降(Kneeling)

Determines to what extent fall impact will affect the object's motion.

Stiffness

This parameter determines how sluggishly the object will react when moved. Low values will make the object sway more as you move around. High values will make the object feel rigid and heavy.

震动速度(Shake Speed)

Determines the ambient shake speed of the object.

TIP: This is a great feature for adding a sense of "documentary" realism. It can really make it feel as if a "real" person is holding the object.

振动幅度(Shake Amplitude)

The strength of the ambient shake. Object will rotate randomly around the X, Y and Z axes. Also, the Y value will be applied to the object's vertical position.

Throw Strength

How much force will be applied to the object when thrown.

Allow Throw Rotation

This will apply a rotation force when the object is thrown, adding an extra dimension of realism.

Burden

A value between 0-1 that will slow down the player while the object is being carried. A value of 1 will slow down the player to a crawl. A value of 0 will make the object have no effect on player speed.

Max Collision Count

The purpose of this feature is to prevent the player from pushing grabbables through walls (and generally to avoid funky physics with external, static objects).

The value determines for how many frames a grabbed object can stay in touch with an external non-kinematic rigidbody (such as a wall, pillar or door) before the player lets go of it. This feature also makes the experience of grabbing things that sit above you on a ledge or a shelf a bit more realistic.

This feature will not detect kinematic rigidbodies, only static level geometry.

A very low Max Collison Count will make the player more prone to accidentally drop an object. A higher value will make it easier to push objects through walls.

Carrying Offset

This applies an offset to the object in relation to the camera. The default is set for a standard unity cube.

Camera Pitch Down Limit

This parameter limits the camera's lower pitch angle while carrying an object. It is recommended to keep the default value (0 = looking straight ahead). Lower pitch values will send the grabbed object into the ground which makes for funky physics. Also, the default value will make grabbing things that sit on a lower ground floor than the player a lot smoother.

Sounds Pitch

This parameter optionally pitches the grab, drop and throw sounds. Variations in pitch should be kept minimal. "X" is "Min" and "Y" is "Max". A typical Min-Max range would be 0.95-1.05.

Grab Sounds

A list of sounds to be played at random when the object is grabbed.

Drop Sounds

A list of sounds to be played at random when the object is dropped.

Throw Sounds

A list of sounds to be played at random when the object is thrown.

Platform Switch Interactable

The Platform Switch Interactable allows control of vp_MovingPlatforms that are set to Target mode for their Path Type. This is useful for opening and closing doors or moving a platform when the player pushes a switch.

Parameters

Switch Timeout

The amount of time in seconds before the player can interact with this switch again.

Platform

A GameObject with a vp_MovingPlatform component should be supplied here. In order for this switch to control the vp_MovingPlatform, it is important that Path Type is set to Target on the vp_MovingPlatform.

Audio Source

An Audio Source that will be used to play the Switch Sounds. If none is supplied, an Audio Source will be added to this object automatically.

Switch Pitch Range

This parameter optionally pitches the grab, drop and throw sounds. Variations in pitch should be kept minimal. "X" is "Min" and "Y" is "Max". A typical Min-Max range would be 0.95-1.05.

Switch Sounds

A list of sounds to be played at random when the switch is triggered.

Switch Interactable

This is a generic switch that allows for the ability to send a single message to another game object. This could be useful for triggering events in your game.

Parameters

Target

The target GameObject that a message will be sent to.

Target Message

A SendMessage is used here to send a message to the Target GameObject.

Audio Source

An Audio Source that will be used to play the Switch Sounds. If none is supplied, an Audio Source will be added to this object automatically.

Switch Pitch Range

This parameter optionally pitches the grab, drop and throw sounds. Variations in pitch should be kept minimal. "X" is "Min" and "Y" is "Max". A typical Min-Max range would be 0.95-1.05.

Switch Sounds

A list of sounds to be played at random when the switch is triggered.

地表系统(Surface System)

The UFPS surface system is responsible for spawning effects caused by collisions and impacts. It is designed to be dynamic, powerful and useful in a broad range of possible physics situations.

Features overview

Surface Effect system

Spawns random sounds (of varying pitch), prefabs (of custom probability) and decals (of random scale) upon impact / collision with objects and players.

Decal Manager

Removes bullet holes if they overlap wall corners, and ages (weathers) remaining ones. Decals may fade and rotate.

Player Foot FX Handler

Handles footstep and footprint effects with three footstep detection modes, along with jump- and fall impact effects.

Rigidbody FX

Rigidbodies can trigger sounds, decals and particle effects dynamically depending on contact with other rigidbodies / terrains or other geometry. Ragdolled bodies can spawn sound and particles when falling to the ground.

Surface Identifiers

These allow you to assign surface type per object, and allows you to disable or enable decals for that object.

Texture fallbacks

Allowing you to identify surfaces depending on terrain- and object textures, supports UV regions within textures.

Default fallbacks

Will figure out the best effect to play in situations where the system doesn't have information about impact- and / or surface type.

Basic surface system logic

 

An ImpactEvent goes into a SurfaceType, which triggers a SurfaceEffect.

  1. A typical in-game situation is that a projectile, footstep or rigidbody script sends a raycast and an ImpactEvent into a collider.
  2. The SurfaceType of that collider responds to this by triggering a SurfaceEffect at the raycast hit point.
  3. The SurfaceEffect finally spawns particles, decals, objects and sounds into the scene.

How does it all fit together?

Quick script overview

The SceneManager group

UFPS scenes should have a hierarchy called 'SceneManagers', each containing a 'SurfaceManager', a 'DecalManager' and a 'PoolManager' gameobject. A ready-to-use prefab for your new scenes can be found under 'Base/Content/Prefabs/SceneManagers'. Note that after dragging this prefab into your scene, you may want to add scene-specific textures to the SurfaceManager's 'Texture Fallbacks' (this is required if you want footstep and bullet effects on terrains). Also, note that the pool manager is deactivated by default in the prefab. This is because it requires some understanding that can be confusing to beginner scripters.

vp_SurfaceManager

Has fallback SurfaceTypes derived from the textures of the target objects. Also has default fallbacks for (potentially missing) impact- and surface types. One per scene (optional).

vp_DecalManager

Handles the fading out (weathering) of decals, and smart removal of any badly placed decals. One per scene (optional).

vp_PoolManager

Handles recycling of prefabs that frequently die and reoccur. Saves lots of memory and is good for performance. One per scene (optional).

ScriptableObjects

vp_SurfaceType


The main surface concept in UFPS, used for spawning effects on projectile or footstep impact (and potentially many other things).

vp_SurfaceEffect

A recipe for a bunch of effects to be spawned in response to a certain type of collision.

vp_ImpactEvent

Identifies different collision types for surface effect and damage logic purposes. Typical ImpactEvents are: BulletHit, FallImpact, Footstep, ItemDrop, etc. Typically assigned to vp_FXBullet, vp_PlayerFootFXHandler and vp_RigidBodyFX scripts. One per bullet fired / footstep placed.

Scripts that sit on scene objects

vp_SurfaceIdentifier

Associates scene colliders with SurfaceTypes. Sits on any and all scene objects, whether static or moving around. One per collider (optional).

vp_PlayerFootFXHandler

Sits on the player body. Handles any and all effects that emanate from the feet of the player, from footsteps, jumps and fall impacts.

vp_RigidbodyFX

Sits on scene props and the player ragdoll. Triggers any and all effects that emanate from physics objects colliding with other objects and terrain.

Scripts that sit on effect prefabs

vp_FadingDecal

Can be used to make decals (and other objects) rotate, shrink, fade and die when finally invisible.

vp_ParticleFXPooler

Handles proper pooling of particle effects, whether using the Legacy or Shuriken particle system.

Surface Manager

The vp_SurfaceManager component can be used to trigger effects depending on object textures, reducing the need for assigning a vp_SurfaceIdentifiers to gameobjects in the scene. It also has default fallbacks for (potentially missing) impact- and surface types. Using a scene SurfaceManager is optional but recommended. Without it, default fallbacks and terrain effects (among other things) won't work.

 

The SurfaceManager will try to derive the surface type of a raycast hit from various sources, including single textures, textures among multi-materials, and terrain textures. It is also possible to define UV regions for textures inside its editor (i.e. for atlas maps).

  • There should be one SurfaceManager in every scene, with textures specific to that scene.
  • If no vp_SurfaceManager is present, particle effects will only trigger if the target object has a vp_SurfaceIdentifier component.
  • The surface system has some notable limitations that it's good to be aware about. Please see this section for more info.

Texture Fallbacks

To create a new SurfaceType fallback for a texture group, click 'Add Texture Group' and be sure to assign a vp_SurfaceType. Then, add all the textures you want associated with that particular surface type by clicking Add Texture Slot. You can clear and remove slots by clicking the little [x] button. You can remove an entire SurfaceType by clicking the [Remove] button at top right of the foldout.

UV overlap

Click the [UV] button to restrict a surface to within a rectanguar region inside a texture. If two texture fallbacks share the same texture and have overlapping UV, the one that is higher up in the list will always be selected, and any other underlying ones will never be selected. To solve this problem, make sure the UV regions of identical textures do not overlap. Note that if you want to have several surfaces inside a single texture, you need to add the texture to a slot once for every UV region.

Default Fallbacks

These fallbacks will be used when the system can not determine the ImpactEvent and/or SurfaceType involved in an impact. This can happen due to a projectile not having its vp_ImpactEvent set, or a target object lacking both a vp_SurfaceIdentifier and a texture fallback. See this section for more info on the runtime logic.

Impact Event

This is the impact type that will be used when the impact type is unknown (for example: a footstep or bullet has no impact type). The fallback will apply to all cases when the impact type is unknown, unless a surface type has an effect assigned to the contact fallback.

Surface Type

This is the impact type that will be used when the surface type is completely unknown (for example: an object has no surface identifier, and none of the object- or terrain surface fallbacks triggered for it. Your fallback surface can be one of the existing surfaces, but it is important that it has all the impact types in your game hooked to an effect, including the fallback impact type

Allow Decals

When 'Allow decals' is false (recommended) default fallbacks will not be able to spawn decals, even if the vp_SurfaceEffect has them. This will prevent fallback decals that don't fit well with the target surface.

TIP: Fallbacks are very powerful, as they will allow you to provide rough behavior for all the surfaces in your game with all FX combinations accounted for - with an absolute minimum amount of work.

Dealing with stretched decals

Due to Unity engine internals, childing a decal to an object with non-uniform scale (meaning x, y and z scale are not identical) will result in decals that are strangely stretched / warped on such objects.

Therefore, objects that are non-uniform will only receive decals if the DecalManager's "Allow Non Uniform Decals" is true.

If the object has only slight scale deviations on one or more axes, the warping of the decals may be very slight and acceptable, but if scale deviations are considerable, decals will start to look very bad when childed to the object.

There are three different workarounds for this:

  1. If the target object should never move or be destroyed at runtime you should make it static. this will make decals appear normal on its surface, however decals won't be actually childed to the object.
  2. To prevent decals from ever spawning on any non-uniform object, you can add a decalmanager to the scene and uncheck its "Allow Non Uniform Decals".
  3. If you need the problematic object to be moved or destroyed at runtime, but want to otherwise allow non-uniform decals, you can solve this on a per-object basis. add a surface identifier to the object and uncheck its "Allow Decals" toggle.

  • You should never move or destroy the static an object at runtime (or decals will be left floating in the air behind it).
  • If there is no DecalManager in the scene, this is the default behavior.

Impact Events

The vp_ImpactEvent ScriptableObject is used to identify different collisions types for surface effect purposes. It declares (by filename) a particular type of collision that will be used to trigger effects when sent into a collider that has a SurfaceType.

Typical ImpactEvents are: BulletHit, FallImpact, Footstep, ItemDrop, etc. When a bullet hits a rock floor, the ImpactEvent is what makes the SurfaceManager spawn sparks, dust and a ricochet sound instead of a footstep sound. To achieve this, vp_ImpactEvent objects are bound to vp_SurfaceEffect objects inside an encompassing vp_SurfaceType object.

Creating a new ImpactEvent

Fallback ImpactEvent

You can set a global fallback ImpactEvent in the SurfaceManager -> Default Fallbacks, for cases where the impact event is unknown (for example: someone forgot to set an ImpactEvent on a bullet component).

When you have created a new ImpactEvent, it must be assigned in at least two places to do something:

  1. A vp_FXBullet, vp_PlayerFootFXHandler or vp_RigidBodyFX component. These are the objects that send ImpactEvents.
  2. A vp_SurfaceType object (bound to a vp_SurfaceEffect object). Alternatively: as the default ImpactType fallback in a SurfaceManager component (bound to the default fallback SurfaceEffect).

TIP: The vp_ImpactEvent script itself doesn't really 'do' anything, and it has no settings. It is just used as an 'ID card' for a certain type of impact, which can be easily dragged around in the editor and assigned to slots. Of course, at runtime it plays a very important role in the communication between footsteps / bullet / rigidbody fx scripts and the surface system.

Surface Types

 

The vp_SurfaceType ScriptableObject is the main surface concept in UFPS. Surfaces will trigger effects in response to projectile, rigidbody and footstep impacts (and potentially many other things). Every surface has a list of ImpactFX' structs, each binding an ImpactEvent to a SurfaceEffect for every type of collision effect response you want to cover.

Recommended usage

The recommended usage is for most of your scene prop prefabs to have vp_SurfaceIdentifier components with vp_SurfaceTypes assigned to them. This is the most performant way for UFPS to look up a surface. When a projectile, fall- or footstep impact hits an object, UFPS will have the SurfaceType instantly, and will look for the ImpactEvent in the 'ImpactFX' list. If found, the corresponding SurfaceEffect will be played. If not, the SurfaceManager (if any) will try to revert to a good fallback effect.

Creating a new SurfaceType

 

ImpactFX

'ImpactFX' lists all the ImpactEvents that are supported by this surface type - that is: the ImpactEvents that can result in a certain SurfaceEffect being triggered when hitting this SurfaceType.

Add or remove elements to the list by increasing or decreasing the number.

IMPORTANT: Be very careful when decresing this number, since if you decrease it too much, the last elements in the list will be destroyed.

ImpactEvents and SurfaceEffects

Whenever a projectile, fall- or footstep impact occurs, the vp_SurfaceManager looks for the particular SurfaceType + ImpactEvent combo here. Click the little circle icon to the left of each field to see the Project's available object types. If found, the resulting SurfaceEffect is played. If not, the SurfaceManager (if any) will try to come up with a good fallback effect.

Defining a fallback effect for when the ImpactType is unknown

  1. Make sure the SurfaceManager has a default ImpactType fallback
  2. Open the SurfaceType object and create a new element
  3. Add the same fallback ImpactType as the SurfaceManager's default one
  4. Assign any effect to it

Allow Footprints

When walking on this surface, should vp_PlayerFootFXHandler send extra info (regarding foot and direction) to the SurfaceManager? This setting will only work if there are fx with decals in the ImpactFX list. Keep this setting off unless you need it. For performance reasons you should only enable footprints on soft ground surfaces like snow, mud or sand.

Surface Effects

 

The vp_SurfaceEffect ScriptableObject is a recipe for a bunch of effects to be spawned in response to a certain type of collision. It might trigger when a bullet hits a wall, or when a player makes a footstep, or falls violently to the ground.

Each object contains the data references and logic for a simple one-shot effect. When triggered, it plays a random sound from a list, spawns a bunch of prefabs (according to random probabilities), along with optionally a randomly scaled decal (via vp_DecalManager).

It is important to understand that a SurfaceEffect object itself is never spawned, as a prefab. Instead, it gets triggered and responds by playing sounds and itself spawning prefabs. The SurfaceEffect object doesn't exist at the "Scene level", but at the "Project level".

Creating a new SurfaceEffect

声音(Sound)s

When the SurfaceEffect triggers, one AudioClip from 'Sounds' will be randomly chosen and played.

Min & Max Pitch

If these values are 1, the sound will be played as-is. With any other values, the pitch of the sound will be multiplied by a random value inside this range.

Max One Per Frame

Enable 'Max Once Per Frame' to avoid excessive sound volume on impact with effects that triggers many times at once (such as shotgun pellets).

Objects

预制体 预设体 预制组件(Prefab)

All prefabs in this list will attempt to spawn simultaneously, success depending on their respective 'Probability'. Perfect for particle fx and rubble prefabs!

Probability

A value of 1.0 means the prefab will always spawn when this SurfaceEffect is triggered. A value of zero means it will never spawn (useful for temporarily disabling the object).

TIP: When spawning rubble prefabs, consider adding a vp_RigidbodyImpulse script to the prefab to give it some initial velocity.

Decal

When this SurfaceEffect is triggered, one prefab from the list will be randomly chosen, spawned, surface aligned and added to the decal manager cueue, for fading out over time.

IMPORTANT: All prefabs are assumed to have a MeshFilter and MeshRenderer on their main transform with a classic 2-triangle quad (normal aligned with the Z-vector). The overlap detection features of vp_DecalManager require this type of decal (!).

Min & Max Scale

When the decal spawns, its prefab XY (surface aligned) scale will be multiplied by a random value inside this range. Z (forward) scale is not affected.

Allow Edge Overlap

With zero overlap (default) any decals in this effect that overlap the corner of a wall the slightest bit will be removed. When overlap is maxed out (0.5) the decals are allowed to overlap corners all the way to their center. Please note that this feature only works if the scene has a vp_DecalManager component with active 'Placement Tests'. For footprints, this setting is ignored unless your 'vp_PlayerFootFXHandler -> Verify ground contact' is enabled.

Setting up a SurfaceEffect from scratch

  1. Create some FX content (the sounds, particle fx and decals of your effect) and name them something suitable. These are the effects that will be triggered together when the impact happens.
  2. Create or duplicate a vp_SurfaceEffect  object. This is the container for the effects. It ties together all the sounds, particles and decals under a common name and defines how they should be spawned.
  1. Assign sounds
  2. Assign particle prefabs
  3. Assign a decal (if needed)
  1. Create or duplicate an ImpactType object (or use an existing one). This is the event / message that will be sent to the SurfaceManager to trigger the effect. The impact event can be triggered from script by projectiles, rigidbody impacts, fallimpacts, footsteps and so on.
  2. Add the ImpactType and SurfaceEffect to the "Default" surface object. This will make the ImpactType work on most / undefined / unkown surfaces.
  1. Open the Default SurfaceType, increase the size of its "ImpactFX" array by one and unfold the new, last element in the list.
  2. replace the impacttype and surfaceeffect with your new impacttype and surfaceeffect

  1. Make something spawn the ImpactType, that is, assign it to a slot in script designed to work with the UFPS surface system. This could be any of the following scripts:

Surface Identifiers

The vp_SurfaceIdentifier component is used to determine what effects should emanate from the surface of an object when hit by impact events, such as bullet hits, footsteps, fall impacts and rigidbody collisions.

It is recommended to rely on SurfaceIdentifiers first and foremost when making your game, and only resort to the more advanced SurfaceManager features for special cases (like terrains and multiple material objects). If you make it a habit to put SurfaceIdentifiers on all your prop prefabs, they should "just work" by default no matter what scene you use them in.

SurfaceType

This field determines what the object's surface is made of, and what vp_SurfaceEffect it will trigger when it gets hit by something. Click the little circle icon to the right of the field to see a list of the project's available SurfaceTypes.

TIP: If the list is empty, make sure to select the "Assets" tab of the popup window, rather than the "Scene" tab.

Allow Decals

This toggle determines whether bullet holes and footprints can stick to the surface of this object. It will override any SurfaceManager settings for this particular object. Useful for objects that have colliders that do not perfectly follow the shape of the object and thus will get bad decal placement.

Surface ID

This parameter can be safely ignored. It is only provided for backwards compatibility with the old ufps 'vp_FootstepManager'. It is not used by vp_SurfaceManager and will be removed in a future release.

Enabling blood effects on the player

  1. Add a vp_SurfaceIdentifier to the controller
  2. Assign the default 'Flesh' SurfaceType.

This will make the player emit blood fx and flesh sounds when hit by bullets. To replace the demo sounds and effects by custom ones, select the 'Flesh' SurfaceType and modify it.

If the player has a ragdoll hierarchy, you may also want to do the same on at least the torso colliders (usually one for the chest and one for the lower torso). This will make the ragdoll emit blood effects even when the controller has been disabled. Of course, nothing prevents you from going to town and assigning SurfaceIdentifiers to all of the ragdoll colliders.

Decal Manager

vp_DecalManager is a per-scene system for capping the amount of decals in the level and removing badly placed ones in non-intrusive and elegant ways. The system can be tweaked for realism vs performance in a very flexible manner.

Decal Limits

By default there can be 100 decals in the scene. As new decals appear, older ones are weathered and eventually removed. The weathering and "100 decal cap" work by default in a static fashion (no need to add a component). If the scene has a DecalManager, the limits can be tweaked.

Total

Only this many decals will be allowed in the scene at any given time.

Weathered

This sets how many of the oldest decals will participate in a gradual process of fading just a tiny bit each time a new decal gets spawned (the oldest of these will be almost invisible).

  • Weathering is not based on game time, but on the amount of decals in the scene and the order in which the decals were created.
  • Every time a shot gets fired (or footprint placed), "weathered" decals loose a slight percentage of their opacity in one step.
  • If no shots are fired, a 50% weathered decal can sit - half transparent - in the world indefinitely. As soon as a new shot gets fired, again the decal looses a slight percentage of its opacity in one step.
  • As a decal eventually becomes invisible it gets removed from the scene.

Placement Tests

Typically, decals are considered "badly placed" if they don't sit firmly and entirely on the parent object. For example: a bullet hole has been fired into the corner of a wall and one or more of its quad corners are outside the wall, making the bullet hole appear as a thin, flat sticker partly hovering in the air. This can be tested against using additional raycasts at the quad's vertices. Since excessive raycasting can be a performance issue, the DecalManager has settings to keep the amount of raycasts at any given time to a minimum. Depending on your target platform you can disable placement tests or significantly reduce the amount of testing.

Cleanup over time

When enabled (recommended) the DecalManager will slowly and gradually check all decals in the scene for surface contact. Over time, all failed decals will be removed.

TIP: In this respect, the DecalManager is like a janitor who tries to prevent decals from getting placed in buggy ways. If it gets overhelmed with too many decals it will pause, but patiently remember and clean the world of all badly placed decals over time. Slowly but surely only well placed decals will remain.

Vertex Raycast Interval (sec) and Decals Per Batch

On each interval (in seconds) one batch of decals somewhere in the scene will each have one corner (vertex) tested for surface contact.

Instant quad corner test

When enabled, any decals spawning within range of the camera will have all four corners raycast for surface contact immediately. On fail, the decals will be removed.

Quad Raycast Range

Decals within this range of the camera will have all four corners raycast for surface contact.

Max Quad Raycasts

Only this many quad raycasts will be performed each second. Additional ones will be buffered. Every VertexRaycastInterval seconds, one remaining quad corner somewhere in the scene will be tested for surface contact.

Allow Stretched Decals

With this setting enabled, objects with non-identical X, Y and Z scales will also receive decals (with a risk of stretched decals). See this section for info on how to deal with stretched objects.

Removal on Fail

These settings determine how any badly placed decals will be removed.

Delay

When a decal has been flagged for removal (but stays on screen) it will postpone fading out for this many seconds.

Fadeout Speed

Lower values will make flagged decals fade out slowly. Maxing out the slider will make them disappear instantly.

Insta-remove if offscreen

If enabled, any decal that has been flagged for removal will disappear instantly if the player looks away from it, a "now it's there - now it's not" trick ...

Fading Decals

 

Use this manipulator on decals (or any other objects) to spawn animated surface effects for footsteps on soft wet mud, cooling plasma gun impacts and more. The decal will always fade out and can optionally be made to shrink and rotate. When it reaches below 0.1 alpha it will be destroyed.

Fadeout Delay

The decal will wait this many seconds before it starts to fade out.

Fadeout Speed

Affects the speed of fadeout.

Shrink Delay

The decal will wait this many seconds before it starts to fade out.

Shrink Speed

Affects the speed of shrinking.

Rotate Delay

The decal will wait this many seconds before it starts to spin around its forward vector (Z).

Rotate Speed

Baseline Z spin speed.

Rotate Accelerate

If this is enabled, the rotation speed will gradually increase.

Player Foot FX Handler

 

This component handles all effects that emanate from the feet of the player, including from footsteps, jumps and fall impacts. It supports three footstep detection modes: 'Detect Body Step' (from animation), 'Fixed Time Interval' and 'Detect Camera Bob' (same as classic UFPS). The system delegates all effect spawning to the UFPS surface system by sending it vp_ImpactEvents.

Except for triggering fx that may be detectable by a human player in multiplayer, this component does not affect gameplay. For example: Fall impact effects are handled by this script, but fall impact damage is handled in 'vp_PlayerDamageHandler'.

Below is a component reference exaplining all parameters in detail. If you're in a hurry, you may want to skip ahead to the following footstep tutorials instead:

Setting up a Foot FX Handler on your player

Adding new footstep sounds to your game

Setting up footstep sounds for multiplayer

Footsteps

Mode

Detect Body Step

 When using this mode, the timing of the footsteps will be determined by the animation and you don't necessarily have to create separate states for e.g. Run and Crouch.

In this mode, footstep effects are placed on the ground under the correct foot whenever it returns down after having moved above the "Detect Height" plane. It is the most "intuitively realistic" mode. However please note that results are very dependent on the quality of your animation and tweaking a good "Detect Height" to suit it.

To enable this mode:

  1. Set both foot gameobjects to a gameobject on the left and right foot of your body model, respectively.
  2. Set the footstep interval to 0.0 (default).

Fixed Time Interval

In this mode, footsteps will be placed according to a timer, and the horizontal foot position will be used to place footprint effects at ground level. Each foot will trigger effects whether touching the ground or not (but this is hardly noticeable since feet are usually fairly close to the ground and moving fairly fast).

Use this mode if you want a different / more controlled footstep rate than that resulting from the animation - or if you don't have an animated body model but you still want particles to appear where the feet would have been. This is great if your character animation somehow produces irregular footsteps (making the character sound like it's limping).

In this mode, you may want to create separate states with custom intervals for e.g. Run and Crouch.

A typical "Interval" is 0.35.

Interval mode with player body feet
  1. Set both foot gameobjects to a gameobject on the left and right foot of your body model, respectively. OR if you are not using a body model, child two empty gameobjects to your controller, one slightly to the left and one slightly to the right of the center. then asign them to the left and right foot slot, respectively, and footsteps will be nicely spawned under your controller even though it has no animated body.
  2. Set a footstep interval. 0.4 is a good default interval. in this mode, the player can also slow down the default rate of the footsteps smoothly using an analog controller such as a gamepad

Interval mode with "dummy" feet

This mode is what you want if your game is not using a player body model.

  1. Set both foot gameobjects to "None"
  2. Set a footstep interval. 0.4 is a good default interval. in this mode, the player can also slow down the default rate of the footsteps smoothly using an analog controller such as a gamepad

Detect Camera Bob

This is the classic UFPS footstep detection mode. It is designed for a player with no body (a "floating camera") and works by detecting when the camera bob "dips", that is: reaches its lowest value and ascends again. Obviously it requires your camera to have bob motion enabled. The following settings on your vp_FPCamera component will determine footstep rate: Bob -> Amplitude -> Y Bob -> Step Threshold

Impact Event

This determines what ImpactEvent your player's feet will send to the underlying SurfaceType when walking. The SurfaceType, in turn, will determine what sounds and other effects are played.

This should usually be set to the default UFPS "Footstep" ImpactEvent, but you may want to create additional ImpactEvents for things like different player classes.

Left Foot and Right Foot

you may set an existing bone as the foot transform, but please note that if you are planning to use footprints later on (e.g. on snow, sand), then it's usually better to place a specific gameobject since the forward vector of the foot transform will be used for determining the direction of the footstep. also, adding a specific gameobject for this allows more control over the foot position for footstep detection.

Trigger Height

A typical 'Trigger Height' is 0.15.

Sensitivity

this parameter affects how likely footsteps are to trigger when accelerating from standstill.

it is recommended to begin with this setting at the default (0.5) and tweak only if necessary.

decrease the value if there are too many initial footsteps when starting walking

increase the value if initial footsteps fail to trigger when starting walking

if you are only having trouble with a certain animation such as run or crouch, then you can override this value in the affected state using a preset

Force Always Animate

Due to Unity Culling, the bodies of remote and AI players will stop animating when offscreen, which effectively silences the "Detect Body Step" mode, preventing you from hearing footsteps behind your back (!). This setting will force the Animator component of the player body to animate even if offscreen. It will incur a performance hit but the tradeoff may be worth it for sake of the footstep audio. You will not need to use this setting if your game is singleplayer and your enemies do not use vp_PlayerFootFXHandlers.

Require Move Input

when this is true, the player will only be able to produce footsteps when moving around. when it is false, footsteps will also be triggered when standing still and rotating.

in 'Detect Body Step' mode, it is recommeded to disable this setting for more realism, as this will produce subtle footsteps when looking around, not to mention stepping up or down onto objects / surfaces.

Verify Ground Contact

With this setting enabled (not recommended) the decal system will perform four extra raycasts per footstep (!) to verify ground contact.

Warning: For performance reasons it is recommended to only enable this feature in very special circumstances. See Advanced Topics for more information on the rare cases in which this might be useful.

Jumping

Impact Event

This determines what ImpactEvent your player's feet will send to the underlying SurfaceType when jumping. The SurfaceType, in turn, will determine what sounds and other effects are played.

This should usually be set to the default UFPS "Jump" ImpactEvent, but you may want to create additional ImpactEvents for things like different player classes.

Fall Impact

Impact Event

This determines what ImpactEvent your player's feet will send to the underlying SurfaceType when falling hard onto a collider. The SurfaceType, in turn, will determine what sounds and other effects are played.

This should usually be set to the default UFPS "FallImpact" ImpactEvent, but you may want to create additional ImpactEvents for things like different player classes.

Threshold

Determines the impact force required for a fall to trigger SurfaceEffects. Note that this is a different threshold from the "Fall Damage Threshold" one set on the player's damage handler.

Debug

Pause on every step

This feature allows you to tweak the position of the footstep nodes. It will pause the game every time the player makes a footstep (!). This simplifies tweaking of foot node position and decal prefab scale.

On pause:

  1. Select the node ("LeftFootstep" or "RightFootstep")
  2. Press F
  3. Zoom in (e.g. using the scrollwheel of your mouse)

Mute local footsteps

For tweaking multiplayer footstep sound range with two side-by side standalone executables. When enabled, footstep effects will only trigger if the window is NOT focused. Toggle between the windows a couple of times for this setting to take effect in both windows.

TIP: Footstep sound range is determined by the AudioSource's 'Max Distance' setting.

State and Preset

This works just like adding states for the controller, camera and weapons.

Having  状态(States) and presets usually will only apply to the 'Fixed Time Interval' footstep mode, which is for when you have a player without a body model.

Using a state to temporarily silence footsteps

In some situations you may want to to disable footsteps, for example to Support a crouching or sneaking state where the player should move silent as a mouse. This can be done by creating a state with a preset that sets 'Mode' to 0 (bypass).

Footstep Tutorials

Setting up a Foot FX Handler on your player

  1. Assign a vp_PlayerFootFXHandler component to the 'Body' object of a player hierarchy (typically the child of the main controller that has a 'vp_BodyAnimator' and vp_RagdollHandler' on it, and a body model hierarchy under it).
  2. If you don't have a player body (a.k.a. the "floating camera" setup) then you should attach the component to the same gameobject as the CharacterController.
  3. Under the 'Footsteps' foldout, make sure the 'ImpactEvent' slot has the 'Footstep' ImpactEvent (or another ImpactEvent of your choice). This will make the SurfaceManager spawn the correct fx on different ground surface materials when moving around.
  4. Create two empty gameobjects (one for each foot), child them to the lowest member of the leg hierarchy on each side and place them at the exact middle of the shoe sole (as if the player had stepped in bubble gum). If you don't have a body model, child these to the Controller instead, 50cm apart at ground level.
  5. Assign your new dummy foot gameobjects to the 'LeftFoot' and 'RightFoot' slot, respectively.
  6. If you are using a custom body model and / or custom animations, you may have to tweak the 'Trigger Height' and / or 'Sensitivity' parameters to make footsteps trigger correctly. Make sure the Body gameobject (with this component) is selected in the editor to visualize the trigger in the Scene View while tweaking its height.
  7. Under the 'Jumping' and 'Fall Impact' foldouts, assign the 'Jump' and 'FallImpact' ImpactEvents, or some other ImpactEvents of your choice. This will make the SurfaceManager spawn the correct fx on different ground surface materials when jumping and falling.

Tweaking AudioSources for footsteps

The PlayerFootFXHandler component will cache the AudioSource hierarchically closest to each foot as belonging to that foot. If the feet have no audio sources, the AudioSource of the main CharacterController will be automatically used for both feet. Sound range is determined by the AudioSource's 'Max Distance' setting. UFPS impact FX will mute the sound beyond this range (unlike the default Unity behavior).

Recommended AudioSource settings for footstep sounds

Adding new footstep sounds to your game

  1. Add new footstep audio files to your project
  2. Open, create or duplicate a SurfaceEffect
  3. Open the 'Sound' foldout and replace the existing sound files with your new ones
  4. Open, create or duplicate a SurfaceType
  5. Make sure the SurfaceType has an element with 'Impact Event -> Footstep'
  6. Add the SurfaceType to the footstep element
  7. Add a SurfaceIdentifier to the floor object
  8. Assign the SurfaceType to the SurfaceIdentifier

Setting up footstep sounds for multiplayer

Using 'Muting local footsteps' for multiplayer testing

The vp_PlayerFootFXHandler has a setting called "Mute local footsteps". Since local player footsteps are always played at max volume it can be hard to hear other player's footsteps when testing on your own with two clients runnig on the same machine. This setting makes it so that the footstep sounds on the focused game window will be muted, allowing you to hear footstep sounds from the other game window. If you run by a remote player you will hear your own footsteps, just from the window of the remote player. Run past the other player really close, and then run away until you can no longer hear the footsteps. That's your footstep audio range. Please note that this setting only works for local player footsteps, not for remote or AI players, and not for jump- or fall impact sounds. A recommended footsteprange is 50 meters. This is set using the local player audio source's max distance parameter.

Setting footstep range

Simply open the audio source of the remote player and set the 'Max Distance'. 'Linear Rolloff' versus 'Logarithmic Rolloff' will have quite different results, where linear is more audible over distance. Typically in Unity, sounds will still be audible beyond MaxDistance in 'Logarithmic Rolloff' mode, but UFPS will mute the footstep sound when the distance between the main camera and the transform of the audio source exceeds the max distance, no matter what mode you are using.

To mute footsteps in certain states / during certain player activities, set the controller's 'MotorFootstepInterval' to 0 (zero) for that state. For example, to have footstep sounds only play when the remote runs, you could set the 'MotorFootstepInterval' to 0.4 in the run state, and to 0 in the 'Default' and 'Crouch' states. Footstep sounds will never play in the 'Dead' state.

Making footsteps audible behind your back

By default, remote player footstep sounds using the "Detect body step" mode will not play behind the local player (that is: you can not hear footsteps occuring behind your back, no matter how close). this is because Unity stops animating (culls) off-screen animated characters: there are no footsteps to detect because the model is not animating. if your game requires the local player to be able to hear footsteps behind his back (recommended) then this can be fixed in two ways:

  1. Go into the remote player prefab, locate the "vp_PlayerFootFXHandler" component and make sure "Force Always Animate" is on. This will force the Animator component of all player bodies to animate even if offscreen and will incur a performance hit but the tradeoff may be worth it for sake of the footstep audio.

     ... OR ...
  2. If you don't want to make this tradeoff, consider changing footstep mode on the vp_PlayerFootFXHandler to "Fixed Interval". This will allow you to hear footstep sounds behind your back, with no animation performance hit from offscreen characters, although footstep effects will play out of sync with animations.

Rigidbody FX

This script can be placed on a Rigidbody object to make it spawn SurfaceEffects and object sounds upon collision with external surfaces. When a rigidbody hits a certain surface, it plays a bash sound specific to that surface, and lets the surface spawn any additional effects such as particles and decals. For example: An object hitting rock can make the terrain eject dust and pebble particles - along with a gravely sound - while an object hitting metal could make the metal clang, but with very subtle particle effects (if any). A wooden crate might make a hard, rattly sound when hitting rock, but a softer, muffled sound when bouncing on grass. And so on. If the ImpactType is left blank the SurfaceManager will try and come up with fallback effects.

  • This (the incoming) Rigidbody object will not emit effects, only the external (impacted) surface will. However, the Rigidbody object can be made to play its own special sounds on impact depending on the hit surface, making for a real good combinatory effect.
  • Note that this component does not determine what decals and sounds to attach to the object's surface when hit by something else (like bullets, or footsteps). That functionality is handled by vp_SurfaceIdentifier.

Impact Event

This sets what ImpactEvent the Rigidbody will send to external objects upon collision.

The default ImpactEvent used on all rigidbodies in the UFPS demo scenes is 'RigidbodyCollision'. This ImpactEvent is represented in all SurfaceType objects with suitable effects assigned.

The SurfaceType of the hit objects will determine what sounds and other effects are played. If ImpactEvent is left blank, the SurfaceManager will try and come up with fallback effects that may or may not make sense.

This setting is what makes dust / blood / paint / rubble / debris come off of the other object.

Impact Threshold

Determines the impact force required for a collision to trigger SurfaceEffects.

Min Camera Distance

This sets how close a Rigidbody must be to the local player in order for the effects to spawn. An optimization in order to prevent massive amounts of effects potentially spawning in hectic games / large worlds, especially when the game initializes and all the physics objects come to rest.

Collision sounds

This is a list of sounds that should emanate from this object in response to collision with specific SurfaceTypes.

TIP: If you don't want to spend time and energy setting up a specific sound for every prefab and surfacetype in the game, just assign the 'Default' SurfaceType along with a sound into one slot. This is a good way of providing a generic effect that is still specific to the surface hit.

Making a Rigidbody emit SurfaceEffects on collision

  1. Make sure the gameobject has a Rigidbody component.
  2. Assign an ImpactEvent. This is the type of impact that the object will impose on other objects.
  3. Define what object sounds this object should make upon collision with a defined collection of world SurfaceTypes. These are the sounds that will emanate from the object itself upon collision.

Item pickup ground drop effects

If you want item pickups to have a sound when they pop out of a crate and fall to the ground:

  1. The item pickup must have a Rigidbody and an audio source. the audio source should have its "Volume Rolloff" set to "Logarithmic Rolloff" and a "Max Distance" of about 20. (In UFPS the pickups that adhere to this standard are the ones with the "Loot" suffix in their names. The hovering ones (and the health loot one) don't.
  2. Add a vp_CollisionFXSpawner component to the pickup
  3. Set the vp_CollisionFXSpawner's "ImpactType" to "ItemDropGeneric". This will produce a generic dust particle effect for all item pickups. But of course you can create specific ImpactTypes and SurfaceEffects for different types of item in your game, such as clothes, swords, food, etc.
  4. increase the size of the "Collision Sounds" array and assign the sounds that should play on all the different surface types in your game

Adding ragdoll drop effects

Making the player body emit sounds and particles when killed and collapsing on the ground can be very dramatic.

  1. Assign a vp_RigidbodyFX component to the transform of the "Hips" or ragdoll collider.
  2. Set the ImpactType to 'RagdollDrop'.

This should be enough for the ragdoll to spawn ground surface particles and sounds when it dies and falls down. Theres no need to make any other settings, although it might be fun to add a collision sound to the head saying "ouch" ;).

TIPS: You may want to experiment with different colliders depending on your own particular ragdoll setup, whether your game is 1st or 3rd person, singleplayer or multiplayer etc.

  • In our tests, the "Hips" collider had a more realistic particle and audio position, but had a slight tendency to trigger more than once per fall. Also, it had a tendency to play the sound panned either to the left or the right speaker. This may or may not be acceptable with your colliders and sound effects.
  • The "Head" collider usually resulted in slightly better audio timing and centered sound, and fewer duplicate triggerings but would obvisously emit particles and sound originating from the head. Depending on your camera and character setup, and how ambiguous your particle effect is, this may or may not be the best tradeoff.

Advanced Surface System Topics

Surface Manager

Fallback logic

Limitations due to system architecture

Limitations due to Unity architecture

TIP: If you have an object with multiple materials that should only have the same surface type, for performance reasons it is a good idea to just put a vp_SurfaceIdentifier component on it.

Footsteps

声音(Sound)s

UFPS will cache the audiosource hierarchically closest to each foot as belonging to that foot. If the feet have no audio sources, the audiosource of the main charactercontroller will be automatically used for both feet. Having footstep sounds emanate from _exactly_ the correct position in 3d space would theoretically be desireable in e.g. Virtual Reality - but please note that for a regular human character the difference between having one audiosource per foot and using a single one inbetween the feet incredibly slight. Also, it is likely to create falloff and doppler issues since the distance from the feet to the audio listener (on the camera) will fluctuate a lot as the character walks and runs. For humans, audio will usually be more 'stable' with a single audio source at the bottom center of the character controller.

Verify ground contact

When enabled, every footstep will be extra carefully checked for surface contact using quadruple raycasts, like bullets. This might be useful in case your character has just stepped in blood or mud AND there is a ledge or staircase nearby (to remove the risk of footprints partly hovering over floor edges).

For performance reasons it is obviously recommended only to enable this feature in very rare and special circumstances. Footprints usually always spawn within the decal manager's quad test range, meaning there will be a huge increase in raycasts made from the player. Also, these tests will spam the DecalManager's cleanup process, delaying tests for bullet decals which are vastly more likely to have bad placement.

In summary, it's almost always overkill to verify ground contact for footprints and they seldomly overlap edges anyway (stairs are rarely carved from footprint materials like sand or mud).

Then again, perhaps your game supports bloody, or muddy feet and lots of stairways? If so, whenever the player got his feet wet, set the 'VerifyGroundContact' bool to true on his 'vp_PlayerFootstepTrigger' component using script, then set it back as fast as you humanly can when the liquid has dried off.

TIP: You can visualize quad-raycasting for footsteps by enabling 'Show raycast points' in the decal manager's debug section.

Choosing a footstep detection mode

Detect Body Step

Detect Camera Bob

Fixed Time Interval

Automatic body animation sync

YES

-

-

Camera & weapon bob sync

-

YES

-

Foot to ground touch timing

YES

-

-

Detects standing still and turning

YES

-

YES

No need for states and presets

YES

YES

-

No body model required

-

YES

YES

100% control over footstep rate

-

-

YES

Works in 3rd person        

YES

-

YES

Detect Body Step

Pros

Cons

Detect Camera Bob

Pros

Cons

Fixed Time Interval

Pros

Cons

Bullets

Choosing a bullet script

vp_FXBullet

This is the standard hitscan bullet script for UFPS. It's the only bullet script with built in compatibility with the UFPS surface system. Always use it for new projects.

vp_Bullet

Use this as a base class for your own awesome hitscan-bullet class, or use it as-is if you just need an invisible raycast to damage or tractor-beam something.

vp_HitscanBullet

This is the legacy bullet system for UFPS. Only use this if you are porting an old game to a newer UFPS version purely for bugfix updates, or relying on it for your own classes based on legacy UFPS versions (for example: your own surface system) or if you find its features sufficient and you're not planning on using the new UFPS surface fx system. Existing projects should have vp_HitscanBullet replaced by vp_FXBullet. See the releasenotes for UFPS 1.6 for an upgrade guide.

Pooling

Why use vp_PoolManager?

When a pool manager instance is not present in the scene, Unity's regular 'Object.Instantiate' and 'Object.Destroy' will be used to spawn and kill objects. This feeds the garbage collector and potentially causes performance issues. Pooling will do a world of difference in terms of runtime object allocations when shooting and blowing stuff up, especially with the surface system which spawns a lot of particle effects. Pooling (recycling) of objects will always occur if the vp_PoolManger script is placed on a game object in the scene and enabled, saving lots of memory. When a pool manager instance is found, 'vp_Utility.Instantiate' and 'vp_utility.Destroy' will forward execution to vp_Poolmanager.Spawn' and 'vp_Poolmanager.Despawn, respectively.

Preventing bugs when pooling objects

Please keep in mind that objects must always be re-initialized in 'OnEnable' instead of 'Awake / Start' when using pooling. Failing to meet this requirement will often result in strange and hard to find bugs (such as every other grenade not exploding). For this reason, when you run into strange bugs, always remember to test with the pool manager deactivated. If things work all of the sudden, there's a big chance you need to move your MonoBehaviour's initialization from 'Awake / Start' to 'OnEnable'.

Adding prefabs to the pool manager's ignore list is an option that will solve many issues while still allowing you to still use the pool manager. For example: when things start working only every other time (e.g. a prefab or system only working every other time it is spawned) - then this is indicative of a pool manager issue and you could try adding suspected culprit prefabs to the ignore list.

Particle FX

Particles and pooling is a bit tricky in Unity. Make it a habit to always put the vp_ParticleFXPooler script on every one-shot particle fx prefab (!) to enable it for use with the vp_PoolManager system. Without this script, most Shuriken particle systems will be left in the scene forever (unless you destroy or despawn them manually). Similarly, without this script, any Legacy particle systems that use 'AutoDestruct' will be destroyed and garbage collected (instead of pooled) and the ones that don't will be left in the scene forever (unless you destroy or despawn them manually). It's a very useful script if you fire guns a lot.

地表系统故障修复(Surface System Troubleshooting)

Surface related

I have a level geometry whose material / shader does not have a texture. How to associate it with a surface?

Add a vp_SurfaceIdentifier component on the object

My surface fallback does not work

Make sure that there is not a vp_SurfaceIdentifier component on the target object: it will override all fallback settings.

I have put a vp_SurfaceIdentifier on an object but it does not seem to work

  1. Verify that you have assigned a surface type
  2. If you want it to receive decals, verify that 'allow decals' is enabled on the surfaceidentifier
  3. Verify that there is only one surfaceidentifier on the object
  4. Verify that the object has uniform scale and if so, give it a uniform scale or make it static

SurfaceEffects don't work on a static, multi-material / atlas map object

This is a very unfortunate limitation due to Unity architecture. When you make an object "rendering static", Unity merges the meshes together in a way that prevents UFPS from deriving material info / texture coordinates for fx spawning. At time of writing there is three known solutions to this problem:

  1. Make the object non-static. This may be OK if it's not for all level geometry but just a few objects. It is required for using atlas maps.
  2. Place invisible, static colliders above floors or walls with a certain texture, and assign a surface manager to the invisible object
  3. Don't use multi-material objects = break the objects up into separate, static objects.

Bullet and decal related

Bullets make the wrong (or no) sound when hitting the player

  1. Verify that the controller has a vp_SurfaceIdentifier on it with the 'Flesh' SurfaceType
  2. Verify that the bullet type that hits the player has its ImpactType set to 'Bullet'

Trouble getting decals to show on a uniformly scaled object

  1. Make sure the object has uniform scale (same scale on all axes), or go to 'SurfaceManager -> Placement Tests -> Allow Non Uniform Parents -> ON'
  2. If suitable, make the object static. This should be OK for any level props that will never move and can not be destroyed, unless they have multiple materials that you want to each have a different surface fx (decal). In that case: you must split the object up into separate single-material static objects and assign a surface identifier.
  3. If the object has a surface identifier component, make sure its 'Allow decals' setting is enabled.
  4. If the object has no surface identifier or its texture has not been added to the surface manager, try setting 'SurfaceManager -> Default Fallbacks -> Allow decals -> ON'. However, note that this will allow decals for all fallback effects in the scene.

Trouble getting decals to show on a non-uniformly scaled object

  1. Make the object static and make it has uniform scale (same scale on all axes).
  2. If that doesn't work, verify 'SurfaceManager -> Default Fallbacks -> Allow decals', aswell as the 'Allow decals' setting of any vp_SurfaceIdentifier on the object.

In a standalone build, decals show up as stretched on a non-uniform, static object

This is a Unity bug in versions prior to Unity 5.4 What happens is actually that objects loose their static flag when loaded at runtime (!). If you see stretched bullet decals on a non-uniformly scaled, static object that exists in a level that is loaded at runtime (e.g. for multiplayer) then you can fix it in two ways

  1. Upgrade to Unity 5.4.x

    ... OR ...
  2. Make the object have uniform scale.

Also, see this section.

Decals have not been removed when an objects respawns

Make sure the bullet decal is in the "Debris" layer

Footstep related

Footsteps won't trigger in 'Detect Camera Bob' mode when I'm walking slowly, backwards or crouching

Camera bob step detection is very sensitive and this is likely a tweaking issue

The algorithm works by detecting when the camera bob sinus curve reaches its lowest point and starts going back up. Depending on the speed of the character, the sinus curve will have different "shallowness" which may affect detection.

When moving and turning fast, footsteps may sometimes fail to trigger, since turning slows the character down which dampens camera bob. this is a limitiation of this mode, rather than a bug.

If your game supports different controller states with their own speeds (e.g. Run, Crouch) then tweaking the values for each state is especially important for this to work consistently.

  1. Amplitude -> Y: making this more pronounced may solve the issue
  2. Step Threshold: reducing this value (even all the way down to zero) may solve the issue
  3. Try speeding up the character (since this magnifies camera bob).
  4. If the problem arises only when the character is backing up, try increasing Bob Y amplitude or your vp_FPController's 'Motor -> Backwards Speed' setting

No footsteps / effects on terrain

  1. Verify that the level has a vp_SurfaceManager component with all the splat textures used on the terrain assigned to Texture Groups
  2. Verify that each Texture Group is assigned to a surface type
  3. Verify that the surface type has impact events and surface effects set up properly
  4. Verify that the surface effects have sounds, particles and / or objects in it
  5. Note that vp_SurfaceManager was designed for use with - and is only guaranteed to work with - the standard Unity Terrain component.


VR

Introduction

UFPS has a simple VR integration intended as a starting point for your own VR research and experimentation.

What is the VR integration?

  • TIP: Should you run into trouble getting any of this to work, check out the VR Troubleshooting section.

What is it not?

A full-featured VR FPS framework with support for many input flavors, VR platforms or hardware. Moving beyond the starting point described above, every VR game will have its own design quirks and favored input models, a vast possibility spectrum not covered by this feature set (or by support). That said, UFPS 2 will have more native VR support and likely broader platform support.

For an overview of limitations and unsupported features, please see this section.

Input model

The basic gameplay setup is similar to the early VR demo of 'Doom BFG Edition' and a number of VR ports of existing FPS games, that is: the weapons are fixed to the head view of the player and are rotated to point where you're looking, with sway.

When pressing forward, you move in the direction you look. Besides being a standard approach, this allows desktop FPS games to be ported to VR without the need to rewrite a ton of stuff.

The "Comfort mode" is an example of locomotion and input designed to prevent nausea due to simulator sickness. It uses a popular teleport locomotion model where you point something to the ground nearby (in this case your gaze) and press a button to instantly go there (note that the "pointer" used does not need to be your head, it can be anything).

  • TIP: At some point, be sure to read up on nausea due to mismatch between the human visual and vestibular systems a.k.a. "simulator sickness" in the primer offered by Oculus here.

Requirements

... OR a Gear VR with a bluetooth gamepad

Setup

Project Settings (IMPORTANT)

  1. Go to "Edit > Project Settings > Player > (PC, Mac and Linux Standalone) > Other Settings > Graphics APIs for Windows"
  2. Make sure "Direct3D11" is present in the list. If not, add it using the [+] button.
  3. If present, remove "Direct3D9" from the list using the [-] button.
  4. Make sure to check the 'Virtual Reality Supported' checkbox.

Install OVR Plugin

  1. Install the proper OVR Plugin for your specific version of Unity 5 (depending on your Unity version, this may or may not be necessary.        https://developer.oculus.com/documentation/game-engines/latest/concepts/unity-ovrplugin-132/
  2. Import Oculus Utilities for Unity 5

https://developer.oculus.com/downloads/game-engines/1.3.2/Oculus_Utilities_for_Unity_5/

        https://developer.oculus.com/documentation/game-engines/latest/concepts/unity-integration-req/

Script execution order

  1. Go to 'Edit > Project Settings > Script Execution Order'  and verify that the following scripts are added at the very bottom, in the following order:

vp_VRCameraManager

vp_VRWeaponManager

vp_VRCrosshair

vp_VRPainFlash

vp_VRTeleporter

vp_FPInteractManager <- NOTE: You must drag this from the top to the bottom for proper interaction in VR.

  1. Press Apply to save the changes

Demo scenes setup

IMPORTANT:

  • Always remember that after pressing play in the Unity editor, a game will not receive proper input until the 'Game' window has focus! This means: after pressing play, you must click once in the 'Game' window before you put on your headset, or input won't work.
  • Before playing these scenes, make sure you have performed the above installation steps, then make the following input settings for playing each respective demo.

UFPS_VR_Comfortable

(GAMEPAD ONLY)

Make these settings before play

  1. Drag an 'OVRCameraRig' into the scene root from the 'OVR/Prefabs' folder and save the scene. (NOTE: not an 'OVRPlayerController').

TIP: The easiest way of finding the prefab is just to type "ovrc" in the Project View search box. When dragging, be sure not to accidentally child the object to another object. It should sit in the root.

  1. Go to 'UFPS > Input manager' and set 'Control Type' to 'Joystick'
  2. Bind the 'Teleport' secondary button to 'Joystick Button 0' (klick the rightmost button and press the 'J' key on your keyboard twice to find it)
  3. Bind the 'Jump' secondary button to 'None'
  4. Press play to start the game and make sure there are no red errors in the console.
  5. IMPORTANT: Before taking your headset on, make sure your gamepad is on, and click once in the editor 'Game' view to give it focus.

'Comfortable' demo details

This mode is the safest one from a nausea-perspective and works great for casual games, slow paced games and puzzle games.

UFPS_VR_Moderate

(GAMEPAD RECOMMENDED)

Make these settings before play:

  1. Drag an 'OVRCameraRig' into the scene root from the 'OVR/Prefabs' folder and save the scene. (NOTE: not an 'OVRPlayerController')
  2. Go to 'UFPS > Input manager' and set 'Control Type' to 'Joystick'
  3. If you unbound 'Jump' when playing the "Comfortable" demo, rebind it to 'Joystick Button 0'
  4. Press play to start the game and make sure there are no red errors in the console.
  5. IMPORTANT: Before taking your headset on, make sure your gamepad is on, and click once in the editor 'Game' view to give it focus.

'Moderate' demo details

This mode is a more traditional FPS setup, with some modifications to prevent nausea.

UFPS_VR_Intense

(GAMEPAD OR KEYBOARD & MOUSE)

Make these settings before play

If you are going to be playing with gamepad

  1. Go to 'UFPS > Input manager' and set 'Control Type' to 'Joystick'
  2. If you unbound 'Jump' when playing the "Comfortable" demo, rebind it to 'Joystick Button 0'
  3. Press play to start the game and make sure there are no red errors in the console.
  4. IMPORTANT: Before taking your headset on, click once in the editor 'Game' view to give it focus.

'Intense' demo details

This mode is suitable for action-packed desktop FPS games that happen to come with a "bonus VR mode".

Keep in mind that the Input Manager "Control Type" setting is important and will result in confusion if it's not properly matching the input hardware, so remember to go back and change this setting if changing input hardware later.

Custom player and scene setup

If you are only about to try out the demo scene then you don't need to bother with the following yet (instead, read the demo scenes setup chapter and head back here later). But if you are ready to port existing scenes / player prefabs, go ahead and read on.

Overview

It's important to note that no VR gameobjects or components are added to the UFPS player. Instead, the player co-exists with an OVRCameraRig and gets manipulated at runtime by a bunch of "vp_VR" scripts in a separate gameobject. This design requires a minimum of player prefab setup, and allows you to toggle the VR mode on and off seamlessly when testing in the editor.

Workflow

  1. Make sure you've done all the Setup steps.
  2. Put one of the prefabs from the 'VRModes' folder + an OVRCameraRig in the scene to run UFPS in Oculus VR mode.
  3. Deactivate the VRMode gameobject to run the game "as usual" with Oculus VR disabled (the OVRCameraRig will be auto-disabled). You can toggle the gameobject on and any time (even at runtime) to toggle VR on and off.

Scene root objects (not childed to each other)

The player object

A regular UFPS player with a VR camera setting enabled

OVRCameraRig

The default prefab supplied by Oculus (NOTE: this is not the OVRPlayerController)

VRMode prefab

A gameobject with the vp_VRCameraManager (required) and a bunch of optional "vp_VR" scripts. The pre-configured ones are: 'VRModeComfortable', 'VRModeModerate' and 'VRModeIntense'.

TIP: Toggling the VR mode is not intended as a game feature, but more as a development convenience. Perhaps you don't want to spend the whole a day with a headset on and there may be some gameplay features and visual aspects of the game that you're able to tweak and test in desktop mode. In this case, you can just disable the VRManager prefab and the game will be instantly playable in regular desktop mode.

Player Camera VR setting

The vp_FPCamera needs a single setting to get working with VR (although you will also want to adjust the weapon positions later).

In your player prefab, go to the vp_FPCamera component's 'Rendering' foldout and verify that its 'Disable VR mode on startup' setting is ON (checked). When the vp_FPCamera wakes up, this will temporarily disable the setting 'Virtual Reality Supported' found under Project Settings, and re-enable it when needed. It leaves it up to the game scripts to re-enable the 'UnityEngine.VR.VRSettings' boolean when appropriate.

This may seem counter-intuitive, but it's an important feature that will allow toggling between regular Desktop mode and the OVR Camera Rig at runtime. It will allow you to test-run the game in "normal mode" without having a headset on. Without it, the desktop camera view won't render correctly when the VR mode is disabled and mouse and gamepad will not work in the editor.

TIP: 'Disable VR mode on startup' is only applied in the editor. You can change that by commenting out the the #if UNITY_EDITOR line at the bottom of vp_FPCamera.Awake.

Body

The VR integration currently does not support the body system. This is because the body system is based on desktop view rendering tricks, and because VR with motion tracked headsets demand some quite complex IK. In short, it requires a new body system, and this is planned for UFPS 2.

Adjustments

If your game is VR only

If your game supports both Desktop and VR modes, and you need the player body for Desktop mode

Footstep sounds

Since the body object gets either deleted or disabled in the current setup, you need to create an additional vp_PlayerFootFXHandler specifically for the VR mode. This can not rely on an animated player body, and so needs to be added to the main player gameobject and use a footstep detection mode that does not rely on the animated player body.

  1. Add a vp_PlayerFootFXHandler to the root player gameobject (the one that has a CharacterController).
  2. Set 'Footsteps > Mode' to 'Fixed Time Interval'
  3. Set 'Footsteps > Require move input' to ON.
  4. Under the 'States' foldout, click the 'Add State' button three times and add the states "Zoom", "Crouch" and "Run" (top to bottom),
  5. Search the project for, and assign, the text presets "FootFXFixedTimeZoom", "FootFXFixedTimeCrouch" and "FootFXFixedTimeRun" to the respective states.
  6. Disable the vp_PlayerFootFXHandler component (!). We don't want it to compete with the one on the body gameobject (if any). It will be automatically enabled when needed.

  • When the VR controller is active, this foot fx component will be enabled, and the one on the player body (if any) will be disabled along with the player body.
  • By default, footstep fx will trigger at the bottom center of the controller. if you want the footsteps to emanate from more realistic positions slightly to the left and right, see this section (step 4).

Camera adjustments

Procedural Motion

Note that you don't need to worry about disabling potentially nauseating features on the camera component itself. This can be done on the vp_VRCameraManager. For more info see this section.

Death state

Since there's no ragdoll, the camera will revert to using its death state when the player is killed. You should tweak this for a slightly higher position that in default UFPS, or the headset camera will probably clip the ground in many situations. See the included preset 'VRCameraDead' as an example.

Reload state

The Reload camera state is unnecessary in VR and may cause irritating, subtle sliding of the camera view, for example: when pressing the reload / interact button without having a weapon wielded. However, it must not be removed entirely from the camera, because this will mess with player auto reload logic. Instead, keep the Reload state on the camera but make sure the preset is empty ('None').

Other unnecessary camera states

Revise your camera states to remove any states that are only suitable for desktop play. Have a look at the camera states in the 'VRHero' prefab for a good minimum setup.

Weapons adjustments

You will want to modify at least the following weapon properties for best appearance in VR (the VRHero uses its ows presets for several weapon states and you can find them in the VR/Presets folder).

Weapon states

The VRCameraManager will automatically disable the weapon camera (!) and this means that the weapons will appear quite different in the headset view (one positive effect of this is that the weapons will now receive shadows, which they normally don't). You will need to tweak the positions in the various states.

The provided weapon VR Zoom states assume that the user will press zoom (aim down sights) and close their left eye (similar to how aiming works in the real world if you are right-eye dominant). You may want to provide two different sets of zoom states to offer a user-preference for this. There is no modification of camera FOV (which is generally discouraged in VR).

回缩(Retraction)

Since there's no weapon camera, by default  the weapons will clip through geometry. UFPS has a feature to alleviate this somewhat: Weapon Retraction.

TIP: If all your weapons have roughly the same length, or you are planning to use the exact same player prefab for VR and desktop mode and don't want retraction for desktop mode, you can force the same retraction distance on all weapons in the vp_VRWeaponManager.

Muzzle & shell eject points

While these can be tweaked by stating relative positions on the components, it's best to add gameobjects for the muzzleflash and shell eject points as described here.

If you want to ship a game that has both a built-in VR and a desktop mode, you will likely have to provide two sets of local player prefabs: one with the weapons adjusted for VR, and one with the weapons adjusted for desktop rendering.

Scene objects

VRMode gameobject

These prefabs have some or all of the UFPS VR scripts, that co-exist with the OVRCameraRig and manipulate the UFPS player. Whenever it is active and enabled, the UFPS player will run in VR mode. Whenever it is disabled (even at runtime), the UFPS player will go back to normal. The prefabs can be found under "UFPS/VR/Prefabs/VRModes"

There are three prefabs to choose from:

  1. Comfortable: A teleport locomotion model (look at ground and press 'Interact' to move) and snap rotation with no camera shakes whatsoever. That said, the player can still be pushed away by explosions.
  2. Moderate: Regular movement input with snap rotation to prevent spin dizzyness. Intended for gamepad use. Has camera shakes from bombs, jumping and falling, but no input bob, shakycam or sway.
  3. Intense: Vanilla UFPS (just with a VR headset). Regular input and crazy bomb shakes, fallimpacts, camera bob when running, the works.

OVRCameraRig

The scene must always have an OVRCameraRig in the root (found under "OVR/Prefabs"). Note that this should NOT be the 'OVRPlayerController', which is not used by UFPS. This script is included in the Oculus Utilities you downloaded in the setup step.

Rigidbody interpolation

Large rigidbodies that the player is able to view close up, should have their "Interpolate" property set to "Interpolate" for smooth movement.

TIP: For existing scenes, make a multi-selection by searching for these instances in the hierarchy view search box by name, and change this setting for all of them at once.

VR Scripts

The 'VR' folder under the UFPS root contains the UFPS VR integration. The first thing to note is that these scripts are not supposed to be attached to the player, but should sit on a gameobject of their own in the scene root. For more info, see the VR Overview section.

vp_VRCameraManager

This component keeps an Oculus VR camera rig attached to the UFPS player controller and enforces headset rotation onto the player pitch and yaw at all times. It also forwards camera shakes (if allowed) and handles input for smooth or snap yaw rotation.

In addition, it has several settings to help you minimize nausea due to simulator sickness, which is an important subject matter to study for any VR game designer.

VR mode forced runtime changes

Procedural motion section

Potentially nauseating features like bob, shake, roll sway and controller sliding can all be disabled on an individual basis in the vp_VRCameraManager script (note that you don't need to disable them on the camera component itself). Bob and shakycam should probably be disabled in most VR games (certainly "Comfortable" ones), but if your game is "Moderate" or "Intense", then the occasional explosion shake could be considered (and is pretty awesome in VR).

Snap Rotate section

This mode is designed to prevent nausea, commonly caused by the camera spinning, and is intended for gamepad use. The player can use the left stick to instantly rotate the camera by 45 (default) degrees, with a footstep effect played for immersion.

By default, this mode uses the horizontal move vector and not a button. This can be changed inside the script (see the snippet in 'vp_CameraManager.cs -> UpdateSnapRotation').

SnapRotate

Should the player rotate by fixed degree steps?

StepDegrees

Step angle in degrees for snap rotation.

MinDelay

Minimum time interval between step rotations.

vp_VRCrosshair

Keeps a cursor prefab hovering in front of the FPCamera, but snapped to the surface of any object we're looking at. If we're not looking at an object, relaxes cursor position away to the a distance from the camera.

CrosshairPrefab

A quad with a crosshair texture and the normal facing along its Z vector.

InteractIconPrefab

A quad with an interact icon texture and the normal facing along its Z vector.

MaxDistance

When aiming at nothing, the cursor will slide to a stop this far away from the camera.

RelaxSpeed

When aiming at nothing, this is the speed at which the cursor will move to the max distance point.

CrosshairMinDistance

When closer to the camera than this, the crosshair will fade out.

InteractIconMinDistance

When closer to the camera than this, the interact icon will fade out.

SurfaceOffset

When aiming at something, the cursor will stop this far in front of it to avoid clipping / fading into it.

HideOnZoom

Should the crosshair be hidden while zooming (aiming down sights)?

vp_VRWeaponManager

This optional script can be used to adapt UFPS vp_FPWeapons for VR camera use. It is intended only for games without hand tracking (so gamepad or keyboard-&-mouse only). The script keeps the weapon pointing in the camera direction, imposes weapon sway from input and headset rotation, and prevents the weapon from rendering at extreme pitch angles where it would otherwise rotate crazily.

RenderPitchLimit

The weapon will be made invisible when looking up or down by this many degrees, to prevent it from behaving erratically.

HeadLookSway

How much should the weapon sway behind when looking around using headlook? (generic for all weapons)

InputSway

How much should the weapon sway behind (horizontally) when looking around using gamepad / mouse? This multiplies the FPWeapon's rotation look sway Y value. Does not work if the VRCameraManager is set to use 'SnapRotate'.

ForcedRetraction

If zero, does nothing. If positive, forces the current weapon's 'RetractionDistance' to this number (same for all weapons). If you want to set this individually for each weapon, keep this at zero and do so on the weapon components (and state presets, if any), but keep in mind that this will affect the desktop game mode (if any) as well.

vp_VRTeleporter

This is an implementation of a popular VR locomotion model by which you point to the ground and press a button to go to new positions. This can significantly reduce nausea due to simulator sickness and works great for casual games, slow paced games and puzzle games.

DirectionPointer

The object that points to the ground to pick a destination point. If not set, the transform of the vp_FPCamera will be set. However, this could be set to any object (such as an Oculus Touch controller).

CursorPrefab

This object will be spawned once, snapped to the destination point and (optionally) made to face the camera at all times.

CursorFacesCamera

If true, the cursor gameobject will be rotated to face the camera at all times. Set this to false if you want to put a vp_Spin script on the cursor.

MaxTeleportDistance

The maximum distance the player will be able to teleport from the current position. The cursor will be visible within this radius unless objects are blocking the way.

MinTeleportInterval

The minimum delay between teleports.

FallImpactDistance

If teleporting to a surface lower than the current position, fall impact will be applied beyond this vertical teleport distance, in relation to the distance.

AllowJumping

If disabled (default), the player will be prevented from jumping at all times even if the jump button is bound. We've found that regular jumping doesn't quite make sense with the teleportation locomotion model.

vp_VRPainFlash

This script piggybacks off the regular UFPS vp_PainHUD to detect when the intensity of incoming damage (and death) and updates a full screen fx plane in front of the camera with pain flashes and blood spatter. The vp_PainHUD is prevented from drawing GUI, and its realtime color values are copied and used by this script instead.

PlanePrefab

A quad with the normal facing along its Z vector. gets texture assigned automatically from the other public properties.

PainTexture

Should be a white texture that fades to zero alpha in the middle. if not set, will be acquired from the vp_PainHUD instance.

DeathTexture

Should be a texture with blood splatter in it. if not set, will be acquired from the vp_PainHUD instance.

距离(Distance)

The distance of the plane from the camera (enforced at runtime).

Limitations and unsupported features in VR

It's good to keep in mind that UFPS was designed for desktop FPS games, and this collection of scripts is mostly intended to save you time by removing some of the research tasks and implementing the workarounds that everyone would have to go through porting an UFPS game to VR.

Moving beyond that starting point, every VR game will have its own design quirks and favored input models (a vast possibility spectrum that can hardly be covered by this framework). UFPS 2 will have more native VR support and likely broader platform support.

The following features / potential features do not work with - and are not covered by support for - the VR integration:

General

UFPS features

VR Troubleshooting

General

"[VRDevice] Initialization of device oculus failed."

This is a problem with Unity not detecting the Rift (unrelated to UFPS). It may be caused by a faulty Oculus plugin installation. Things you can try:

"Error importing folder (The pathName assets/plugins is already mapped to X. But the meta data wants it to be mapped to Y)"

This error will occur if you try to import Oculus Utilities in a too old version of Unity. Make sure you are running at least the version required by Oculus.

"DllNotFoundException: OVRPlugin"

This error will occur if you have a broken installation of the Oculus Utilities. Make sure you are running at least the version required by Oculus and reinstall Oculus Utilities.

The unity editor just crashes when I press play in VR

Make sure that your project's Graphics API is set to Direct3D11. See this installation step for more info.

"There are X audio listeners in the scene. Please ensure there is always exactly one audio listener in the scene."

  1. If there are many of these, always open the console and locate the topmost red error (if any). This is likely the reason.
  2. Make sure the Audio listener on the CenterEyeAnchor object is disabled by default. The vp_VRCamera script will enable it at runtime as needed.
  3. If the above looks OK and you still get tons of these errors, make sure you have installed the Oculus utilities and dragged an OVRCameraRig into the scene and performed all the other setup steps.

VR mode doesn't work / behaves oddly

  1. The VR setup is very sensitive to script / object execution order settings, so make sure your script execution order looks good.
  2. If the VR mode still behaves strange in new levels or won't work at all, you can also try to restart Unity (preferably without saving) and / or delete and re-add all the VR objects, including the player.
  3. Toggling the VRMode gameobject on and off at runtime may help. If you create the player at runtime, try doing this by script after spawning the player.

"Hierarchy error. This component must be added to a gameobject with vp_Weapon components in child gameobjects."

Try to delete the player gameobject and drag the prefab into the scene again. If you have changes on the prefab, don't forget to click "Apply" first.

Headset

Oculus Headset is not tracking

  1. Make sure that your project's Graphics API is set to Direct3D11. See this installation step for more info.
  2. Make sure that the OculusClient.exe is always running in the background.

"Error (vp_VRCameraManager) 'CenterEyeAnchor' is not assigned."

Have you installed the Oculus utilities and dragged an OVRCameraRig into the scene? Before VR mode works, make sure you have done all those things and all the other setup steps described in the setup chapter.

My VR character suddenly seems taller or shorter than normal / I can't reach down to the pickups.

Input

I suddenly can't fire / interact / rotate

Make sure that the editor game window has focus.

I can't fire in a standalone VR build

This seems to be some form of temporary input bug in either Unity 5.3.4 or the Oculus platform.

Here's a workaround to enable firing per game session:

  1. Remove your headset
  2. Click once in the desktop game window to give it focus
  3. Hit escape (removing focus from the game window)
  4. Click once on your desktop, outside of the game window
  5. Click once again in the desktop game window to give it focus. The weapon should now fire.

We'd appreciate any findings regarding this issue.

Snap rotating with the gamepad is unresponsive / slow

Make sure the input manager is set to Control Type -> Joystick.

Snap rotating with the mouse is crazy sensitive

Make sure the input manager is set to Control Type -> Keyboard and Mouse.

Rotating with the right gamepad stick is very sensitive / unsensitive

  1. Go to the Unity input manager at 'Edit > Project Settings > Input'
  2. Unfold 'Axes > Horizontal' (make sure it's the one with 'Type: Joystick'
  3. Set 'Sensitivity' to a suitable value (we found 0.5 to work nicely with the Xbox gamepad on Oculus Rift)

I can't move with the left gamepad stick but rotating with the right stick works

Make sure the input manager is set to Control Type -> Joystick.

I can't rotate with the right gamepad stick but moving with the left stick works

Make sure that the editor game window has focus.

I can't toss a grabbed rigidbody with the fire button using a gamepad

This is currently bound to the top right shoulder button (RB) and not the fire trigger/axis (RT).

Interaction detection seems to be offset by a few decimeters in VR

vp_FPInteractManager must execute last in VR. See this section.

The player slides a little when picking up items by pressing the Interact button in VR

FX

My player does not trigger footstep effects in VR

You may need to assign a vp_PlayerFootFXHandler to the root controller transform. See this section.

Performance

Rigidbody objects move with a stutter

Set the "Interpolation" of all rigidbodies (where this is noticeable) to "Interpolate" for smooth rigidbody movement.

Framerate micro stutter

图像效果(Image Effects)

Image Effects (Unity Pro only) are an awesome addition to any FPS and will give your game that next-gen look. UFPS has been tested with all image effects available in the Pro Standard Assets package (see Image FX compatibility notes). For more information about how to get started with image effects, check out the following links:

http://docs.unity3d.com/Documentation/Manual/HOWTO-InstallStandardAssets.html

http://docs.unity3d.com/Documentation/Components/comp-ImageEffects.html

Important notes

                           No image effect                         Fisheye on FPCamera               Fisheye on WeaponCamera


Rendering Path considerations

The Rendering Path of the two cameras will influence the behavior of image effects.


Forward Rendering

When Forward Rendering is enabled, image effects will work on either the FPCamera (maincam) or the WeaponCamera, as described above.


Deferred Lighting

When Deferred Lighting is enabled, image effects will only work if assigned to the WeaponCamera. The effects will render on both the scene and the weapon.

IMPORTANT: When Deferred Lighting is enabled, the FPCamera (maincam) and the WeaponCamera must use the same HDR setting (on / off), otherwise there will be serious rendering artifacts.

Use Player Settings

If a camera's rendering path is set to Use Player Settings, you may alter it by going to Unity's top menu and "Edit > Project Settings > Player > Per Platform Settings > Other Settings > Rendering Path".

Image FX compatibility notes


Crease

When attached to the WeaponCam this effect will only work on the weapon, not the scene.

DepthOfField

These effects will work best if attached to the FPCamera, though they will only affect the scene and not the weapon. If you wish to blur the weapon and close surroundings but keep the target sharp (for example when sniping) consider instead using the "Vignette and Chromatic Aberration" effect.

Example of the Vignette and Chromatic Aberration effect using Blur

EdgeDetectEffectNormals

This image effect does not currently work with UFPS.

GlobalFog

This effect will not work with Deferred Lighting, and must be assigned to the FPCamera. Hence it will only affect the scene and not the weapon.

SSAOEffect

This effect will not work with Deferred Lighting, and must be assigned to the FPCamera. Hence it will only affect the scene and not the weapon.

SunShafts

If attached to the WeaponCamera, the shafts will only be cast off of the weapon geometry, not the scene geometry (looks cool though).

输入管理器(Input Manager)

The Input Manager allows creating input schemes for keyboard+mouse, touch and gamepad controller. The Input Managerhas the default event types of UFPS preconfigured. It removes the need for most hard-coded keycode checks which means you don't necessarily have to edit scripts to change the controls. The Input Manager can be accessed from the top UFPS menu.

Example scripting usage

All UFPS input should run through the vp_Input class to keep all input in one centralized location. Some examples from vp_FPInput.cs:

// have the player jump continuously while "Jump" button is held

if (vp_Input.GetButton("Jump"))

Player.Jump.TryStart();

else

        Player.Jump.Stop();

// start reload activity when "Reload" button is pressed down

if (vp_Input.GetButtonDown("Reload"))

        Player.Reload.TryStart();

// if user releases 'ENTER', toggle mouse cursor on / off

if (vp_Input.GetButtonUp("Accept1") || vp_Input.GetButtonUp("Accept2"))

Screen.lockCursor = !Screen.lockCursor;

Rebinding controls at runtime

The vp_Input system can be used to rebind controls at runtime (which is not supported by the standard Unity Input Manager). This is done using the method vp_Input.ChangeButtonKey. If its "save" parameter is true, the key for that button will be saved for next runtime. Example usage:

vp_Input.ChangeButtonKey("Jump", KeyCode.G);

Gamepads

Basic setup

  1. To enable UFPS for gamepad use, open the Input Manager and set Control Type to "Joystick". This will enable analog controls. Default bindings have been adapted to the Xbox gamepad.
  2. If you are using a player body, select the Unity Animator component of your player body gameobject and change its "Controller" from "UFPSExampleAnimator" to "UFPSGamepadAnimator". This will allow the legs of your character to move better in sync with fine / slow analog movement.

  • In the default UFPS project the Unity Input Manager has additional, and modified duplicates of some input axes to provide mouselook functionality via gamepad
  • In the editor, gamepad input will only work when the game window has focus (!).
  • Using the Input Manager's secondary bindings for gamepad is handy when working in the editor, since it allows you to alternate quickly between mouse+keyboard and gamepad).
  • If you are using a third party input manager such as cInput or Rewired, then any info here pertaining to the UFPS Input Manager can be ignored.

Setting up basic gamepad buttons and axes for a new project

For a brand new Unity project, the input axes required for gamepads in UFPS will not work by default.

  1. In the top Unity menu, open the Unity (not UFPS) Input Manager by going to Edit -> Project Settings -> Input. Right click on the "Mouse X" foldout -> "Duplicate array element"
  2. In the new copy of "Mouse X", change "Dead" to 0.19, "Sensitivity" to 1 and set "Snap" -> ON.
  3. Change "Type" to "Joystick Axis" and "Axis" to "4th axis (Joysticks)
  4. Right click on the "Mouse Y" foldout -> "Duplicate array element"
  5. In the new copy of "Mouse Y", change "Dead" to 0.19, "Sensitivity" to 0.75 and set "Snap" -> OFF. Also, set "Invert" -> ON.
  6. Change "Type" to "Joystick Axis" and "Axis" to "5th axis (Joysticks)

Setting up Left- and Right Trigger axes as buttons for a new project

  1. In the top Unity menu, open the Unity (not UFPS) Input Manager by going to Edit -> Project Settings -> Input. Increase the size of the element array by exactly two (2). Unfold the first new element and name it "LeftTrigger".
  2. Set "Gravity" to 0, "Dead" to 0, "Sensitivity" to 1 and set "Snap" -> ON.
  3. Set "Type" to "Joystick Axis" and "Axis" to "9th axis (Joysticks). Set "Joy Num" to "Get motion from all Joysticks".
  4. Unfold the second element that you added and name it "RightTrigger".
  5. Set "Gravity" to 0, "Dead" to 0, "Sensitivity" to 1 and set "Snap" -> ON.
  6. Set "Type" to "Joystick Axis" and "Axis" to "10th axis (Joysticks). Set "Joy Num" to "Get motion from all Joysticks".
  7. All remaining settings should be blank / off.

These two new axes are currently hardcored in vp_FPInput.cs. The LeftTrigger will enable the player "Run" state when pressed more than 50%. The RightTrigger will fire the weapon.

Updating the Input Manager for an existing project (pre UFPS 1.6)

If you don't have a lot of custom bindings

  1. The easiest way is to just regenerate the input manager prefab. In the hierarchy view, search for "vp_Input" and delete the prefab with the blue icon.

IMPORTANT: Make sure to not do delete "vp_Input" in the Project view, or you will destroy the UFPS Input manager script.

  1. From the top UFPS menu, click on UFPS -> Input Manager. Done.

If you have lots of custom bindings

  1. In this case it might be quicker to manually add the new required axes to the UFPS Input manager. From the top UFPS menu, click on UFPS -> Input Manager.
  2. At the far bottom of the Input Manager window, click "Add Unity Input Axis" four times.
  3. Set the names of the four new axes to "Horizontal", "Vertical", "LeftTrigger" and "RightTrigger"

In the default UFPS project the Unity Input Manager has modified duplicates of the MouseX, MouseY, Horizontal and Vertical axes to provide mouselook functionality via gamepad. It also has two new custom axes: LeftTrigger and RightTrigger, for gamepad use.

Additional info

基础脚本(Basic scripting)

The vp_LocalPlayer class is a wrapper to greatly simplify scripting with UFPS. It provides global quick-access to the local player and its most common UFPS components. Also, it exposes a number of local player + input properties and methods for quick and straightforward access in a single place.

Accessing vp_LocalPlayer

Just make sure the scene has a proper UFPS local player setup, and you should be able to access the components, methods and properties of vp_LocalPlayer from within any script in the code base. Some examples:

vp_LocalPlayer.MaxHealth = 5;        // set the local player's max health to 5

vp_BodyAnimator a = vp_LocalPlayer.BodyAnimator;  // retrieve its bodyanimator

vp_LocalPlayer.Stop();        // stop the local player in its tracks

TIPS:

  • All vp_LocalPlayer properties make sure to get and set values in the 'proper UFPS way' (where applicable). They also return type defaults in case any component dependencies are null, making them very stable.
  • For pausing, and quick-access to info on the game session, see 'vp_Gameplay'
  • You can inherit the vp_LocalPlayer class to add parameters and methods specific to your own game design

Initialization

The following properties are usually not needed, but may prove useful if vp_LocalPlayer should ever throw nullreference exception:

bool Exists

Returns true if UFPS has been able to cache a vp_FPPlayerEventHandler in the current scene, false if not.

If this returns false (perhaps due to loading, or the local player not having spawned yet in multiplayer), then it is not a good idea to use vp_LocalPlayer calls. If this is the case, try running 'vp_LocalPlayer' Refresh and check 'Exists' again before using vp_LocalPlayer.calls.

Refresh()

Caches the local player event handler in the current scene (as opposed to a potentially null player from the previous scene) along with all of its most common UFPS components.

Position, Velocity, Angles and Directions

Vector3 Position

Gets or sets the world position of the player.

Does not stop the player if moving.

Vector2 Rotation

Gets or sets the world rotation of the player. The controller will rotate around the world Y axis. The camera will rotate around its X and Y axes, subject to pitch and yaw limits. Any body animator will follow suit: the head will rotate along with the camera. The body and feet will only rotate and move if the new direction diverts from the previous controller forward direction by more than 90 degrees. Basically, if you stand still and try to look over your shoulder, your feet and lower body wil readjust to face that direction. If not, your feet will always stay still no matter how much you look around.

Vector3 BodyHeadLookDirection

Returns the direction between the player model's head and the look point. Note: Not necessarily the direction between the camera and the look point (it might be a 3rd person camera)

Vector3 AimDirection

Returns the direction between the weapon model and the look point. In 1st person, this is identical to 'BodyHeadLookDirection'. In 3rd person it is not.

Physics and Velocity

Vector3 Velocity

Gets or sets the current player world velocity. The velocity returned is calculated in the same way as that of Unity's CharacterController. Note that setting this value won't have any effect on player position, it will only affect internal states such as animation speeds (!). To add physics velocity to the player, use 'AddForce'. To forcibly move the player to a position,

use the 'Position' property. To stop the player, use the 'Stop' method. To relocate, rotate and stop the player, use one of the 'Teleport' methods

float Velocity

Returns the overall world velocity of the player controller

AddForce(Vector3 force)

Adds one frame of external force to the player controller, pushing it in the 'force' direction

Move

Forces the player controller to move according to the provided 'inputVector' in joystick format: a Vector2 where X represents sideways and Y represents forward / backward motion with values ranging from -1.0 to 1.0. This needs to be called every frame in 'LateUpdate()'

Stop()

Stops the controller in one frame, killing all forces acting upon it, and snaps all camera motion and zoom to a halt. Note that if you are calling 'Move' every frame, this will not have effect

Teleportation

In UFPS, "teleportation" means moving the player to a new location and look angle, halting all controller forces and camera motions (as opposed to simply repositioning or rotating the player object).

Teleport(Vector3 position, Vector2 rotation)

Moves the controller to the world 'position' and 'rotation' and stops it.

'rotation.x' is camera pitch, and 'rotation.y' is camera yaw

Teleport(float x, float y, float z, float pitch, float yaw)

Moves the controller to the world position (x, y, z), sets the camera angle according to 'pitch' and 'yaw' and stops all controller and camera motion

Teleport(Vector3 position)

Moves the controller to the world 'position' and stops it, without affecting rotation

Teleport(float x, float y, float z)

Moves the controller to the world position (x, y, z) and stops it. Does not affect rotation

Teleport(vp_SpawnPoint spawnPoint)

Snaps the player to a placement decided by the specified spawnpoint, taking into account the spawnpoint's radius, ground snap and random rotation settings. If the player has a vp_Respawner component, its 'ObstructionRadius' setting will be used for obstruction checking. Otherwise the obstruction radius will be 1 meter.

External Objects

Transform LookTransform

Returns the world transform that the player is looking at, within a max range of 2 meters. Returns null if looking into empty space, or if the object has no collider.

TIPS:

  • This can be used to highlight objects that the player is looking at.
  • Use 'GetLookTransform' to set a custom max range (may be more useful for VR and third person)

Transform GetLookTransform(float maxRange, int layerMask)

Returns the world transform that the player is looking at, or null if looking into empty space, or if the object has no collider. This will not return transforms positioned inbetween the camera and the local player (if in third person mode). If 'layerMask' is not provided, then 'vp_Layer.Mask.ExternalBlockers' will be used.

TIP: This can be used to highlight objects that the player is looking at

Transform Ground

Gets the transform of the solid object that the player is currently standing on (if any). Might be the same as 'Platform'. Returns null if the player is jumping or falling.

TIP: Use 'IsGrounded' to simply check for ground contact

Transform Platform

Gets the transform of the platform that the player is currently standing on (if any). Might be the same as 'Ground'. Returns null if the player is not standing on a platform.

TIP: In UFPS, a platform is defined as a solid object that has the 'MovingPlatform' (28) layer (and usually also a vp_MovingPlatform script)

DismountPlatform

Disconnects the player controller from the moving platform it's currently riding on (if any). If the platform is moving, this will make the player slide off of it.

TIP: Use 'AddForce' right afterwards to fling the player off the platform in a particluar direction

bool IsGrounded

Returns true if the local player controller is standing on a solid object, false if not

Health and Death

Damage(float damage)

Applies damage to the player in simple float format, sends a damage flash message to the HUD and twists the camera briefly

Damage(float damage, Transform source, vp_DamageInfo.DamageType type)

Assembles damage in UFPS format from individual parameters and sends it to the player, resulting in damage, a HUD damage flash and brief camera twist. The local player can not damage itself with 'vp_DamageInfo.DamageType.Bullet'

Damage(vp_DamageInfo damageInfo)

Applies damage to the player in UFPS 'vp_DamageInfo' format, sends a damage flash message to the HUD and twists the camera briefly. The local player can not damage itself with 'vp_DamageInfo.DamageType.Bullet'

Die(float painHUDIntensity = 0.0f)

Immediately kills the player and schedules a respawn. If 'painHUDIntensity' is positive, uses it to send a HUD damage flash. The required components are:

vp_FPPlayerDamageHandler (for kill), vp_Respawner (for respawn) and vp_PainHUD (for HUD damage flash)

float Health

Gets or sets player health. The health is not allowed to go above MaxHealth, but negative health is allowed (for things like gibbing)

float MaxHealth

Gets or sets the player's max health. If the value is lower than CurrentHealth, then that will be capped to the new MaxHealth

Weapons and Ammo

SetNextWeapon()

Toggles to the next weapon if currently allowed (present in inventory) otherwise attempts to skip past it (wield the weapon after it)

SetPrevWeapon()

Toggles to the previous weapon if currently allowed (present in inventory) otherwise attempts to skip past it (wield the weapon before it)

SetWeaponByName(string gameObjectName)

Attempts to wield a weapon by the name of its 1st person weapon gameobject as childed under the main FPSCamera gameobject. Will fail if no such gameobject exists, or if there is an inventory script preventing it

SetWeaponByIndex(int index)

Attempts to wield a weapon by the chronological index of its 1st person weapon gameobject as ordered under the main FPSCamera gameobject. Will fail if no such gameobject exists, or if there is an inventory script preventing it

UnwieldCurrentWeapon

Unwields the current weapon, leaving the player unarmed

string CurrentWeaponName

Returns the gameobject name of the currently wielded 1st person weapon gameobject as childed under the main FPSCamera gameobject

int CurrentWeaponIndex

Returns the chronological index of the currently wielded 1st person weapon gameobject as ordered under the main FPSCamera gameobject

int CurrentAmmo

Returns amount of ammo left in the currently wielded weapon (intended for HUD scripts).

int CurrentMaxAmmo

Returns max ammo of the currently wielded weapon (intended for HUD scripts)

int SpareAmmoForCurrentWeapon

Returns extra 'backpack' ammo for the currently wielded weapon (intended for HUD scripts). This method will only work with the UFPS inventory system

Texture2D CurrentAmmoIcon

Returns the Texture2D icon of the ItemType of the currently wielded weapon (intended for HUD scripts). If using the UFPS inventory system, this texture is set on its ItemType scriptable object

First- and Third Person

GoFirstPerson()

Switches to the 1st person view

GoThirdPerson()

Switches to the 3rd person view

ToggleThirdPerson()

Toggles between the 1st and 3rd person views

bool IsFirstPerson

Always returns true if the player is in 1st person mode, and false in 3rd person

Body Hierarchy

Collider Collider

Returns the player collider, most likely a Unity CharacterController

Transform Head

If the local player has an animated body hierarchy, returns the transform of the head bone set on the vp_FPBodyAnimator component. Otherwise returns the transform of the main 1st person camera

Transform LeftFoot

If the player has a foot fx handler, returns the transform of the gameobject set in its 'Footsteps -> LeftFoot' slot. Otherwise returns the transform of the player controller

Transform RightFoot

If the player has a foot fx handler, returns the transform of the gameobject set in its 'Footsteps -> LeftFoot' slot. Otherwise returns the transform of the player controller

Effects

AudioClip DeathSound

This property allows you to change the death sound of the player at runtime

vp_ImpactEvent FootstepFXImpactEvent

This property allows you to change the type of ImpactEvent that the player sends when making footsteps. This makes it easy to change the footstep effects at runtime for different situations or states, such as 'Sneaking', 'Sprinting', 'Wet', 'Wounded' etc. For info on how the surface effect system in UFPS works, please see the manual.

vp_ImpactEvent FallFXImpactEvent

This property allows you to change the type of ImpactEvent that the player sends when falling hard to the ground. This makes it easy to support different types of fall effects for different situations or states. For info on how the surface effect system in UFPS works, please see the Surface System chapter

vp_ImpactEvent JumpFXImpactEvent

This property allows you to change the type of ImpactEvent that the player sends when jumping. This makes it easy to support different types of jump effects for different situations or states. For info on how the surface effect system in UFPS works, please see the manual

Camera Shakes

CameraShake(float force = 0.5f, AudioClip audioClip = null, AudioSource audioSource = null)

Makes the camera shake momentarily as if a bomb has gone off nearby. The default force will be 0.5f unless a 'force' value is provided. You may provide an AudioClip and AudioSource to also play a sound. If 'audioSource' is empty, the main camera's audio source will be used

GroundStomp(float force = 0.5f, AudioClip audioClip = null, AudioSource audioSource = null)

Makes the camera shake momentarily as if a large dinosaur or mech is approaching. Great for bosses! the default force will be 0.5f unless a 'force' value is provided. You may provide an AudioClip and AudioSource to also play a sound. If 'audioSource' is empty, the main camera's audio source will be used

Input

EnableGameplayInput()

Re-enables gameplay input (moving, firing, jumping, reloading, crouching etc.)

DisableGameplayInput()

Blocks the player from moving and sending gameplay input (moving, firing, jumping, reloading, crouching etc.). This does not affect freelook, mouse cursor or GUI input. To disallow these, please see the various 'Mouse' and 'FreeLook' methods

ToggleGameplayInput()

Toggles 1st person gameplay input on and off (moving, firing, jumping, reloading, crouching etc.). This does not affect freelook, mouse cursor or GUI input. To toggle these, instead use 'ToggleMouseCursor' and 'ToggleFreeLook'

EnableFreeLook()

Re-enables camera freelook

DisableFreeLook()

Disables camera freelook

ToggleFreeLook()

Toggles camera freelook on and off

Crosshair

ShowCrosshair

Restores the crosshair texture in case it has been previously hidden

HideCrosshair

Backs up the current crosshair texture and replaces it with an invisible one

ToggleCrosshair

Toggles crosshair visibility on / off

CrosshairTexture

This property allows you to change the crosshair texture at runtime. Here's a very simple script to change the crosshair when it's over an enemy object (remember to set your chosen enemy layer on the target objects)

public int EnemyLayer;

public float Range = 50;

public Texture HaveNoTargetTexture;

public Texture NoTargetTexture;

void Update()

{

if ((vp_LocalPlayer.GetLookTransform(Range) != null) && vp_LocalPlayer.GetLookTransform(Range).gameObject.layer == EnemyLayer)

vp_LocalPlayer.CrosshairTexture = HaveTargetTexture;

else

vp_LocalPlayer.CrosshairTexture = HaveNoTargetTexture;

}

Mouse Cursor

ShowMouseCursor()

Disables freelook and firing, and enables the mouse cursor all over the screen, allowing GUI mouse input such as clicking buttons

ShowMouseCursorAndAllowMouseLook()

Enables the mouse cursor all over the screen and disables firing, while still allowing freelook and body rotation

HideMouseCursor()

Hides the mouse cursor, disabling GUI mouse input.

ToggleMouseCursor()

Toggles mouse cursor and freelook on and off. Please note that hiding the mouse cursor cleanly will only work in fullscreen mode. In the editor, and in windowed mode, the game window must receive a click to hide the mouse cursor

Multiplayer

bool IsMaster

Returns true if the local player is the master of an ongoing multiplayer session. Always returns true in singleplayer. This is a functionality of the 'UFPS Photon Multiplayer Starter Kit'. Manipulate the value using the 'vp_Gameplay' class in case you wish to hook it into another network layer. To check whether the game session is currently in multiplayer or singleplayer mode, you can check 'vp_Gameplay.isMultiplayer'

Accessing components

EventHandler

Retrieves the UFPS player event handler of the local player in the current level, or null if non-existant.

Camera

Retrieves the UFPS camera of the player in the current level, or null if non-existant.

Controller

Retrieves the UFPS controller of the player in the current level, or null if non-existant.

InputManager

Retrieves the UFPS input manager of the player in the current level, or null if non-existant.

DamageHandler

Retrieves the UFPS damage handler of the player in the current level, or null if non-existant.

WeaponHandler

Retrieves the UFPS weapon handler of the player in the current level, or null if non-existant.

库存 背包(Inventory)

Retrieves the UFPS inventory of the player in the current level, or null if non-existant.

Respawner

Retrieves the UFPS respawner of the player in the current level, or null if non-existant.

BodyAnimator

Retrieves the UFPS body animator of the player in the current level, or null if non-existant.

RagdollHandler

Retrieves the UFPS ragdoll handler of the player in the current level, or null if non-existant.

FootFXHandler

Retrieves the UFPS foot fx handler of the player in the current level, or null if non-existant.

事件系统(Event system)

Introduction to the event system

Many UFPS components communicate via a script called the PlayerEventHandler, which is a hub for all local player scripts. This object can be thought of as the nervous system of the player. The event handler decides which activities the player can engage in, and updates all the player's components when activities are being started and stopped.

All scripts that make up the player hierarchy can talk to the event handler - and it can talk to them - but the event handler knows absolutely nothing about what's going on in the connected scripts, and the scripts know little or nothing about each other.

But what's the point of all this secrecy?

Modularity

Objects being unknown to eachother makes for a modular design which is more resistant to brutal changes and is easier to maintain long term. In early versions of UFPS, taking out the weapon switching logic or the camera system would be an arduous process, requiring many surgical procedures before the game would even compile.

In v1.4 a big step was taken towards complete future modularity (although some work remains). In this first version of the event system, difficulty has increased a little for some scripting tasks, while many tasks have gotten easier.

As an example, DemoScene3 uses the vp_PlayerInventory script. This means the player has limited ammo and weapons. Now, if you disable or even delete the PlayerInventory component at runtime, the game will keep running - the player will just suddenly have unlimited ammo and weapons because it no longer understands the concept of "items being limited". The hooks for the inventory system still exist in the player event handler - but no inventory is plugged in anymore.

This makes it easy for you to write your own custom inventory system. As long as it talks properly to the event handler you can code it pretty much how you like, ideally without changing a single line of code in any other FP component (such as the weapon or shooter).

Performance

The event system is designed, above all, for speed. It utilizes core C# engine features for very fast runtime execution, and typically does most of its work on startup, caching information about classes once for fast lookup should it ever need the info again.

Using a fast event system can be crucial on mobile platforms where the regular Unity event system is sometimes too slow.

Understanding event driven code

Brief overview

An event is usually fired as a result of the player pressing or releasing a button. This will activate one of the events declared in vp_FPPlayerEventHandler.cs.

All the methods that are registered as listening to that particular event will then execute. This might be methods all around the code base. It might be zero methods, or an unlimited amount of methods.

Methods that listen to an event always have a listener prefix, such as "OnStart_". For example:

void OnStart_Attack()

This method name tells you the method will automatically be registered as listening to the Attack event when the application starts up, and will execute every time a line of code (anywhere) succeds in calling:

Player.Attack.TryStart();

TIP: To learn more about the various event types, open the vp_FPPlayerEventHandler script and mouse-over on the event types (e.g. vp_Message) for usage info.

TIP: For an example of input related gameflow using events, see Activity example flows.

Finding the lines that SEND an event

To find all the places where an event is sent you can do Find All References on the event in your IDE. If this is not available, you can search the project for the event name preceded by a dot ( . ) For example:

.Reload

Finding the methods that LISTEN to an event

To find all the methods that listen to an event, search the project for its name preceded by an underscore ( _ ). For example:

_Reload

Event handler tutorial

Let's say we want to create an event that prints a string to the Unity console. We don't want the string to be printed by the calling object - instead it should be sent to a target "printer object" - via the event handler.

Preparation

  1. Open the "CleanScene" example scene.
  2. Right click in the Project view > "Create" > "C# Script" > name it "Source".
  3. Create a second script, this time naming it "Target".
  4. Drag both scripts onto the "Camera&Controller" gameobject.

Now, to work with the event system you will typically engage in five different kinds of tasks:

1. Declaring an event

Open the vp_FPPlayerEventHandler.cs script and add a new event declaration:

public vp_Message<string> PrintSomething;

2. Making the PlayerEventHandler available to the scripts

Since our scripts are MonoBehaviours, we need to give them access to the event handler. This is done by adding the below code to both scripts. This will fetch the player event handler object located on the root transform on startup.

vp_FPPlayerEventHandler m_Player;

void Awake()

{

        m_Player = transform.GetComponent<vp_FPPlayerEventHandler>();

}

3. Registering a target script with the event handler

Our "Target" script will have some code to be run, and will need to register properly with the event handler (this is not needed for the sender).

The following code will register and unregister the MonoBehaviour with the event handler whenever the component is enabled or disabled, whenever its gameobject is activated or deactivated, and whenever the gameobject is destroyed. Paste the below code into the "Target" script.

protected virtual void OnEnable()

{

        if (m_Player != null)

                m_Player.Register(this);

}

protected virtual void OnDisable()

{

        if (m_Player != null)

                m_Player.Unregister(this);

}

4. Adding an event listener

Now it's time to add the actual implementation of the printing method. Add the following code to the "Target" script. This is what will be executed when the event is sent.

void OnMessage_PrintSomething(string s)

{

        Print(s);

}

5. Sending an event

In the "Update" method of the "Source" script, add the following code:

if (Input.GetKeyUp(KeyCode.Return))

{

        m_Player.PrintSomething.Send("Hello World!");

}

Now, start the game and press Enter. This should result in the string "Hello World" being printed to the console.

IMPORTANT: Notice that the above code doesn't do just "PrintSomething("Hello World")". Instead it uses the ".Send" before the parenthesis. This is because "PrintSomething" is not a method but an event of type "vp_Message", which is always invoked by its "Send" method. Remember this because it can be confusing at times, especially since different types of events have different invocation syntax.

Event types

There are four general types of event with very varying scripting difficulty level. All types support a single generic parameter (or none). Some event types support generic return values. Some support an unlimited amount of registered methods. Others don't.

vp_Message

Listener prefix: OnMessage_

Invoker: Send

Multiple listeners per event: Yes

Return value: any type (optional)

The standard event type. Takes 0-1 generic arguments and optionally a generic return value. Messages are used for exposing script methods, allowing all scripts that are registered to the event handler to call them. The method name in the target script must have the prefix 'OnMessage_'. Call 'Send' on the event to invoke the method.

An unlimited number of callback methods with the 'OnMessage_' prefix can be added to the same event. For example: there might be 100 methods in 100 different scripts all added to the 'BombShake' event. Now, if a single script calls 'Player.BombShake.Send(1.0f)' every one of those methods will trigger with the argument '1.0f'. A method in a registered script will automatically be added to an event if its name has the prefix 'OnMessage_', followed by the event name. For example, search the project source code for 'OnMessage_BombShake'.

vp_Attempt

Listener prefix: OnAttempt_

Invoker: Try

Multiple listeners per event: No

Return value: bool

An attempt is a simpler form of a message, which supports 0-1 arguments of any type and always returns a bool. It is called using the word 'Try' instead of 'Send'. Its intended usage is for situations when gameplay code needs to ask permission, typically for player actions that may succeed or fail. This event type only supports a single listener (only one method in one script can be hooked up to an attempt).

For example: 'Player.SetWeaponByName.Try("Axe")' can be called to try and switch weapons. If the registered method doesn't think the player has an axe, it should return false. Otherwise, it should switch to the axe and return true. A method in a registered script will automatically be added to an event if its name has the prefix 'OnAttempt_', followed by the event name.

vp_Value

Listener prefix: OnValue_

Invokers: Get, Set

Multiple listeners per event: No

Return value: any type (for 'Get')

This event type exposes a C# property of a single registered script. The generic invocation fields, 'Get' and 'Set', expose their property counterparts. The property name in the target script must have the prefix 'OnValue_'. Use 'Get' and 'Set' to retrieve or assign the property via the event.

Values work basically just like the C# properties they expose. Either the "get" or the "set" accessor can be left out. A property without a set accessor is considered read-only. A property without a get accessor is considered write-only. A property with both accessors is read-write. A listener for a vp_Value looks a little bit different from a vp_Message or a vp_Attempt:

Vector2 InputMoveVector;

Vector2 OnValue_InputMoveVector

{

        get

        {

                return m_MoveVector;

        }

        set

        {

                m_MoveVector = value;

        }

}

vp_Activity

Listener prefixes: CanStart_, CanStop_, OnStart_, OnStop_, OnFailStart_, OnFailStop

Invokers:  TryStart, TryStop, Active, Start, Stop

Multiple listeners per event: Yes

Return value: bool (for 'TryStart' & 'TryStop')

TIP: For a quick intro on activities, you may first want to check out Activity example flows.

vp_Activity is a very powerful event type encapsulating a set of common activity related game logics. It might look a little daunting at first glance, but it's well worth knowing inside out since it is the main workhorse in UFPS input logic.

vp_Activity was designed with the goal of drastically reducing the amount of scripting needed for dealing with complex FPS input scenarios. Using vp_Activity will remove the need for many special cases in the central input script. It handles things like event duration, trigger intervals, scheduled disabling, and most importantly keeping track of what the player can and can't do.

An activity may be active or inactive, and may trigger callbacks when it starts or stops. The activity is typically started or stopped by calling its 'TryStart' and 'TryStop' methods, in which case a list of conditions will determine whether the call succeeds. The activity may also be forced on or off using the 'Active' property or by calling the 'Start' and 'Stop' methods. An unlimited number of conditions and callback methods can be added to the start and stop delegates.

The method names in the target script are categorized into 'conditions' and 'callbacks'. When a 'TryStart' method is called, an unlimited amount of registered conditions for the event may trigger. All scripts that have registered a condition for the activity now have a say in whether the activity should be able to start. If a single script returns false, the activity will fail to start and return false, otherwise true. The same goes for the TryStop command.

New in v1.4.4: By adding an OnFailStart or OnFailStop callback to a script, you can automatically execute code when an activity fails to start or stop. This is useful in cases where you want to react to the result of TryStart or TryStop, but you don't want to modify the core script (for example vp_FPInput) by adding an if-statement to the function call.

New in v1.4.4: TryStart and TryStop each have an optional boolean argument: "startIfAllowed" and "stopIfAllowed". Setting this to false can be used to check whether an activity would start or stop without actually doing anything.

IMPORTANT: Keep in mind that the CanStart_ or CanStop_ callbacks will fire anyway, so to be certain of not executing anything, these should only contain conditionals and no other custom code.

The vp_Activity event optionally supports a single generic argument which can be accessed over the event duration via the 'Argument' property. To learn more about activities in action, it is a good idea to study the various events declared in the vp_FPPlayerEventHandler.cs script.

Activity additional properties

MinPause

Prevents player from restarting an activity too soon after stopping

MinDuration

Prevents player from aborting an activity too soon after starting

        

AutoDuration

Automatically stops an activity after a set timespan

        

Argument

Returns the user-passed argument of this activity,

        

Active

When set, starts or stops an activity and fires its start or stop callbacks (if any).

Start

Starts an activity and fires its start callbacks (if any).

Stop

Stops an activity and fires its stop callbacks (if any).

        

Disallow

Disallows an activity for 'duration' seconds.

Binding states to Activities

The player event handler also has a feature which can bind activities to states. This is done using the method "BindStateToActivity", which can activate or deactivate a state when an activity with the same name is toggled. This is used quite heavily for the example "AdvancedPlayer" prefab, in conjunction with several component state blocking rules.

Activity example flows

Crouch
  1. The player presses the crouch button and climbs under a desk. The Crouch activity's TryStart method returns true and the Crouch activity is set to ON.
  2. The Crouch activity triggers crouching states on the camera and controller. The camera's Crouch state makes it go lower. The controller's Crouch state makes it slow down.
  3. The player tries to stand up again, but the TryStop method of the Crouch activity returns false (we hit our head on the underside of the desk) and the character keeps crouching even though the crouch button has been released.

Jump
  1. On startup the controller adds a condition to the Jump activity (CanStart_Jump), with code stating that this activity may only start if the player is standing on the ground.
  2. The controller also adds a callback to the activity (OnStart_Jump), with code giving the player an upward force when executed.
  3. As soon as the player presses the jump button, the input class will try to start the activity by invoking the "Jump.TryStart" method. This will trigger all the "CanStart_Jump" methods registered throughout the code base.
  4. If any "CanStart_Jump" method in any class returns false, it will prevent the call to "Jump.TryStart" from succeeding. In other words, if the controller class thinks the player is not standing on the ground it will return false, blocking the jump. Otherwise it will return true, allowing the callback "OnStart_Jump" to fire and execute the code to give the player an upward force.

Attack
  1. On startup the inventory adds a condition to the Attack activity, stating that this activity may only start if there is a wielded weapon with enough ammo (according to the inventory).
  2. On startup the weaponhandler also adds a condition to the Attack activity, stating that this activity may only start if the player is not currently reloading. This will result in the following:
  1. If the player presses fire without a weapon, or with a weapon that is out of ammo, the inventory will block the attack.
  2. If the player presses fire while reloading a weapon, the weapon handler will block the attack.
  3. If all of the conditions are met (player has a wielded weapon with ammo in it that is not currently being reloaded) then the attack will succeed and the weapon will be discharged.

What's the difference between an Activity and a State?


计时器 定时器(Timers)

vp_Timer is a system for delaying (scheduling) methods with a time delay. Its design draws on experiences from several animation-, gui- and cinematic heavy game projects. The system supports arguments, delegates, repetition with intervals, infinite repetition and timer canceling. Timers are mostly created using the static method In.

vp_Timer takes a programmatic approach to timing as opposed to content based (as in using animation curves etc). Though you can animate things using vp_Timer, it is primarily a tool for timing things rather than an tool for animating them.

Scheduling actions using vp_Timer.In

vp_Timer.In executes a method after a certain delay in seconds. In its simplest form, it's called with a delay as the first argument and a target method as the second.

// --- EXAMPLE: execute 'SomeMethod' in one second

vp_Timer.In(1.0f, SomeMethod);

void SomeMethod()

{

        // do something

}

You can start a timer that runs forever without executing anything by calling the vp_Timer.Start method.

Iterations (repetition)

To repeat a timer, simply specify a number of iterations after your method name. This will repeat the method a number of times, separated by a timespan equal to the initial delay.

// --- EXAMPLE: execute 'SomeMethod' in one second,
// then repeat it four times with one second inbetween

vp_Timer.In(1.0f, SomeMethod, 5);

vp_Timer.In(0, SomeMethod, 3, 1);

Intervals

If you need the delay between iterations to be different from the initial delay, add the desired interval at the end.

// --- EXAMPLE: execute 'SomeMethod' in one second,
// then repeat it four times with 0.2 seconds inbetween

vp_Timer.In(1.0f, SomeMethod, 5, 0.2f);

If you use iterations with a zero delay and do not specify an interval, the interval will also become zero and all iterations will happen simultaneously (this can actually be used as a short-hand alternative to a for-loop if you want to call a method many times in the same frame).

Arguments

To call a method with a single argument, first create a method of type void with a single parameter of type object. Then you may call the method with an argument of any type right after the method name. In the target method you must cast the object back into the destination type.

// --- EXAMPLE: call a method with a single argument

vp_Timer.In(1.0f, MethodWithSingleArgument, "Hello World!");

void MethodWithSingleArgument(object o)

{

        // use the object directly by type casting it like this ...

        MethodThatTakesAString((string)o);

        // ... or store it as the target type before use like this

        string s = (string)o;

        print(s);

}

If you pass an integer as the third parameter, it will be interpreted as an argument only if there is a corresponding method that takes an object argument. If not, it will be interpreted as an interval.

Multiple arguments

Multiple arguments can be sent to a method by passing them in the form of an object array. In this way you can transfer an unlimited amount of arguments of varying types.

--- EXAMPLE: call a method with multiple arguments

vp_Timer.In(1.0f, MethodWithMultipleArguments,

                  new object[] {"December", 31, 2012});

void MethodWithMultipleArguments(object o)

{

        object[] arg = (object[])o;  // 'unpack' object back into an array

        print(  "Month: " + (string)arg[0]

             + ", Day:" + (int)arg[1]

             + ", Year:" + (int)arg[2]);

}

Delegates

A delegate is basically a pointer to a method. vp_Timer uses delegates to reference the methods you specify via the In method. But nothing prevents you from declaring a delegate right inside the In method. This is where delegates become very interesting. They provide the powerful option of wrapping blocks of code inside a timer without having to create a new method every time.

// --- EXAMPLE: print a console message in one second using a delegate

vp_Timer.In(1.0f, delegate()    {    print("Hello World!");    });

Delegates with arguments

Delegates, too, can be passed arguments in exactly the same way as methods.

// --- EXAMPLE: inflict 'incomingDamage' points of damage after a delay

float incomingDamage = 242.0f;

// add a single object parameter inside the delegate's parenthesis

vp_Timer.In(1.0f, delegate(object o) // <--

{

    InflictDamage((float)o);

}, incomingDamage); // <--

// pass the argument right after the delegate's closing bracket

Delegates with multiple arguments

Delegates can take multiple arguments in much the same way as methods.

// --- EXAMPLE: print the month, day and year variables after a delay

string month = "December";

int day = 31;

int year = 2012;

vp_Timer.In(1.0f, delegate(object o)

{

        object[] arg = (object[])o;        // 'unpack' object into an array

        print(  "Month: " + (string)arg[0]

            + ", Day:" + (int)arg[1]

            + ", Year:" + (int)arg[2]);

}, new object[] { month, day, year }); // <--

// pass the month, day and year variables as an object array right after the delegate's closing bracket

Canceling timers

You can use the CancelAll method either to cancel all currently running timers, or only the ones scheduling a specific method. You can also cancel specific active timers using the vp_Timer.Handle.Cancel method (see the next chapter).

// --- EXAMPLE 1: cancel every running timer

vp_Timer.CancelAll();

// --- EXAMPLE 2: cancel every running timer that schedules 'SomeMethod'

vp_Timer.CancelAll("SomeMethod");

Running a timer forever using vp_Timer.Start

The vp_Timer.Start method can be used to run a timer for the sole purpose of measuring time (useful for e.g. stopwatches). It takes a mandatory vp_Timer.Handle (see the next chapter) as only input argument, has no callback method and will run practically forever. The timer handle can then be used to pause, resume and poll all sorts of info from the timer event

// --- EXAMPLE: start a timer that runs forever

private vp_Timer.Handle m_RaceTimer = new vp_Timer.Handle();

..

void BeginRace()

{

        vp_Timer.Start(m_RaceTimer);

}


vp_Timer.Handle

Timers are typically "fire-and-forget". They are very lightweight and can not be manipulated directly. The upside of this is that for most timers you don't have to do a lot of object creation (the downside, of course, being that you can't really access the timer tself).

vp_Timer.Handle objects are used to keep track of timers post-initiation. Timer handles expose a wide range of useful properties and methods. They are most commonly used to cancel a timer or to see if it's still active, but they also have many properties to analyze the state of a timer (for example, the editor uses them to display debug info).

Creating timer handles

Timer handles need to be created separately, then initialized by passing a vp_Timer.Handle object as the final argument to vp_Timer.In.

// --- EXAMPLE 1: execute 'SomeMethod' in 20 seconds,

// but cancel if user presses space

private vp_Timer.Handle Timer = new vp_Timer.Handle();

..

vp_Timer.In(20.0f, SomeMethod, Timer);

..

if(Input.GetKeyUp(KeyCode.Space))

        Timer.Cancel();

// --- EXAMPLE 2: execute 5 iterations of 'SomeMethod',

// but cancel after 3 seconds

private vp_Timer.Handle Timer = new vp_Timer.Handle();

..

vp_Timer.In(0.0f, SomeMethod, 5, 1, Timer);

vp_Timer.In(3, delegate() { Timer.Cancel(); });

TIP: Placing the handle name on the next line of code can sometimes be good way of highlighting the fact that a timer has a handle associated with it.

Canceling and blocking timers

Timer handles allow you to cancel specific timers whenever you like. They can also be used to prevent scheduling a method multiple times simultaneously, or to cancel a running timer and restart it.

TIP: This is all great for GUI and input cases where users may be "spam-clicking" buttons or toggling quickly between screens, player states or weapons. Without this capability, any "toggling system" using timers may fall into very strange patterns of states flipping on and off.

// --- EXAMPLE 1: cancel and restart a timer on each subsequent call

private vp_Timer.Handle Timer = new vp_Timer.Handle();

..

vp_Timer.In(0.4f, SomeMethod, Timer); // <--

// if 'Timer' is already active, it will be canceled and restarted

// --- EXAMPLE 2: prevent scheduling a timer until the

// timer handle we want to use is free (inactive)

private vp_Timer.Handle Timer = new vp_Timer.Handle();

..

if(!Timer.Active)        // prevents restarting 'Timer' until it's done

        vp_Timer.In(1.5f, SomeMethod, Timer);


Methods

Cancel

Cancels the timer associated with this handle, if active. After a timer has been canceled, the timer handle still exists. You can poll it for (by now historical) data on the timer (for example its scheduled total duration) but some properties will be null and you can't make it execute again. You will sometimes want to check to see if the associated timer is still running using the Active property.

Execute

Executes the timer associated with this handle early, if active. This is useful if you have a scheduled an action that the player should be able to trigger early without canceling it (let's say the player shoots at a time bomb instead of disarming it).

Properties

A multitude of properties can also be accessed from a timer handle. See the comments in vp_Timer.cs for more info.


Debug Mode

Compiling vp_Timer.cs with the DEBUG define will allow you to display debug info on all created timers in the Unity Inspector. This is very useful when debugging complex gameplay. Open the file 'vp_Timer.cs' and at the top of the file uncomment this line:

// --- EXAMPLE: run vp_Timer in debug mode

#define DEBUG        // uncomment to display timers in the hierarchy

Press play in Unity and you should notice a new gameobject "Timers" in the Hierarchy upon the first timer initiated. Select this object and a "Timer" component will become available in the Inspector. Every active timer will be represented in this view as a box with the name of the method being called, its arguments, and optionally the id and callstack info of the function call. When a timer triggers, it will return to the object pool and disappear from view.

IMPORTANT: When done debugging, remember to comment out the DEBUG define again! vp_Timer feeds a lot more junk to the garbage collector in this mode.


Debug info

Created

Shows the total amount of timer objects created during this session. This will be the same as the maximum number of timers ever having been active simultaneously.

Inactive

This number represents the amount of timers that have been recycled and may be used for subsequent scheduling.

Active

This number represents the amount of currently active timers.

Show Id

Displays the Id of the call to vp_Timer.In or vp_Timer.Start that (re)activated this timer. This is an ever growing number, i.e. each Id of such call is unique.

Show Callstack

Displays a stack trace (a list of the function calls that led up to the timer being initiated). This is very useful for debugging, especially if you are using lots of delegates and have no method name to go by.

TIP: If you really need to name delegates for debug purposes, schedule them using a string with a name of your choice as the argument. The nametag will be visible in the list between the parentheses of the delegate.


反作弊(Cheat Detection)

Anti-Cheat Toolkit is a very powerful third-party product designed to detect the most commonly attempted cheats, and trigger code in response to cheating. UFPS has a light ACTk integration, adding basic support for Anti-Cheat Toolkit's ObscuredTypes to the UFPS remote player wizard, state and preset systems.

While no system can make a game 100% cheat resistant, Anti-Cheat Toolkit can aid you in making life a little bit more frustrating for typical cheaters, making it harder to hack your game with off-the shelf cheating programs.

TIP: Reading the ACTk readme is highly recommended to get a basic understanding of what the system does and doesn't do.

Setup

  1. Install 'Anti-Cheat Toolkit' from Unity Asset Store.
  2. To enable the UFPS-ACTk integration, go to:
    'Edit > Project Settings > Player > Other Settings > Scripting Define Symbols' and add the following string to the text field:

    ;ANTICHEAT
  3. As soon as Unity has recompiled, UFPS will have basic support Anti-Cheat Toolkit's ObscuredTypes.

ObscuredTypes Scripting Guide

While using most of ACTk's detectors is trivial, when implementing ObscuredTypes into an existing project full of prefabs, you should tread lightly to avoid loss of prefab data. The following is a guide on how things can be simplified within the UFPS framework.

KEEP IN MIND:

  • While the ObscuredTypes Detector is arguably the most powerful one, it is also the most intrusive one, because it requires changing the hard coded types of your variables.  Because of how Unity serialization works, this will reset the affected values to default in all your gameobjects and prefabs! This can not be prevented using inheritance, or in any less intrusive way (that we know of).
  • For example: making the firing rate of vp_Shooter an ObscuredType will result in all your weapons reverting to the same, default, firing rate and you need to be creative about preventing or reverting this.
  • For this reason (and to some extent because every game has its own anti-cheating requirements) the UFPS-ACTk integration does not change the types of any variables by default, but leaves this up to you as a game developer, to be approched on a case-by-case basis.

When to implement ObscuredTypes?

Implementing them has no gameplay functional consequences per se. They pretty much work like regular variables of the corresponding type (with a couple of minor exceptions).

The best stages of a project to switch to ObscuredTypes might be when you are just starting out, and / or when you don't expect to be updating UFPS again for the remainder of the project (likely best). If you however do need to make an UFPS update, see this tutorial for info on how to retain serialized ObscuredType values in prefabs.

All that said, when you have ObscuredTypes up and running it is very powerful and a surefire way to frustrate your cheaters!

Changing a variable in ANY SCRIPT into an ObscuredType

PLEASE NOTE: This will revert the value to default in all prefabs using the particular script. This can not be avoided unless the script inherits from vp_Component (see the next tutorial for a list of such scripts).

  1. At the very top of the script, add the following line:

using CodeStage.AntiCheat.ObscuredTypes;

  1. Change the variable declaration to use the corresponding ObscuredType. The ones supported by UFPS are:

ObscuredFloat

ObscuredVector3

ObscuredVector2

ObscuredInt

ObscuredBool

ObscuredString

For example:

public float MaxHealth;

        ... becomes ...

public ObscuredFloat MaxHealth;

Changing a variable in a UFPS SCRIPT with a STATE MANAGER into an ObscuredType

The following approach is only possible for UFPS scripts that are descendants of vp_Component AND that have a custom editor. This is true for:

vp_FPController

vp_FPWeapon

vp_FPWeaponShooter

vp_FPWeaponMeleeAttack

vp_FPCamera

vp_FPInput

vp_FPInputMobile

vp_Weapon

vp_WeaponShooter

vp_Shooter

vp_PlayerFootFXHandler

  1. At the very top of the script, add the following line:


using CodeStage.AntiCheat.ObscuredTypes;

  1. We can't prevent Unity from reverting the value to default inside prefabs, but we can back up all values to text presets and load them back in afterwards. So basically:
  1. Figure out all the prefabs that use the script you will be modifying (e.g. for a vp_FP script: one or more player prefabs).
  2. Under the 'Preset' foldout at the bottom of each component, click 'Save' and do so to a unique text file per prefab.
  1. Change the variable declaration to use the corresponding ObscuredType (see the previous tutorial if you are unsure about this).
  2. Save the script and let Unity recompile. Unity will proceed to merrily reverting the value to its default in all prefabs.
  3. For all the prefabs that share the modified script, under the 'Preset' foldout at the bottom of each component, click 'Load' and load the text preset you saved for this prefab earlier. The value will go back to what it was before you made it an ObscuredType.

TIP: For the UFPS multiplayer add-on, you don't need to use this approach for remote player prefabs, instead just do it for the local player prefab, and regenerate the remote player afterwards.

Where to use ObscuredTypes?

This is to some extent dependent on your game design, but of course there are some no-brainers for most (especially multiplayer) game designs. Keep in mind that ObscuredTypes incur a performance hit, so don't necessarily go crazy with every variable in the game. The following scripts hold variables that you may want to harden for a typical (especially multiplayer) game.

vp_DamageHandler

Health of players and breakable objects

vp_Regenerator

Regenerating player and object health

vp_PlayerDamageHandler

Falling damage

vp_Shooter

Most aspects of weapon firing

vp_WeaponShooter

Tap-firing rate

vp_UnitBankInstance

In-weapon ammo

vp_FPController

Lots of things governing general player motion

vp_Controller

Flying, jumping and gravity

For more info on UFPS-ACTk integration for multiplayer, see the UFPS Photon Multiplayer Starter Kit manual.

Preventing obscured value reset in prefabs when updating UFPS

This tutorial assumes you have made no other direct changes to the UFPS source code except changing variables to use ObscuredTypes, and that the UFPS Script directory folder structure has not changed in the new update. It doesn't cover all cases - it's just to show an overall approach.

  1. Make sure to have a detailed list / good idea of all the variables you have changed to use ObscuredTypes.
  2. Backup your project / commit your scripts and prefabs to a revision control system so you can always revert if things go wrong.
  3. Import the new version of UFPS into a new blank project.
  4. Close Unity and do not open it again until done (!).
  5. Go into the asset folder of the new project and copy the UFPS 'Scripts' folder on top of your own project's 'Scripts' folder, replacing all files. All your ObscuredTypes will now change back to regular types and this is bad.
  6. Without opening Unity until ready: Reimplement all the ObscuredType declarations manually (or use a Diff tool creatively).
  7. When done, open Unity. Hopefully the ObscuredTypes in your prefabs will not have reverted to their default values.
  8. Now you can attempt to import the new UFPS version, but in the import dialog remember to deselect all scripts.

Additional scripting notes

'Unsupported type' editor error message

This can happen when a the Unity custom editor (likely of a script prefixed 'vp_FP') becomes confused that a type has changed. It might especially be spammed to the console when dragging a slider. It's not serious but of course very annoying. To remove the error:

  1. Make a note of the component's vertical order in the gameobject's list of components in the Inspector
  2. Click the little cog wheel  on the top right of the component in the Inspector > "Copy Component"
  3. Cog wheel  > "Remove Component"
  4. Cog wheel  > "Paste Component As New"
  5. The refreshed component will be pasted at the bottom of the list. This may upset some in-game logics. Restore the order of the component (that you noted in step 1) by clicking the cog wheel  > "Move Up" one or more times.

ObscuredTypes do not work with the ternary operator

(The ternary operator is the question mark '?' sometimes used in C# to shorten simple if-statements.)

For example, the following code:

float damage = (float)Mathf.Abs((float)(DeathOnFallImpactThreshold ? MaxHealth : MaxHealth * impact));

        ... must be unrolled into this:

float damage;

if (DeathOnFallImpactThreshold)

        damage = MaxHealth;

else

        damage = (MaxHealth * impact);

There is no Vector4 ObscuredType

At time of writing, Vector4 is not supported by ACTk, and therefore the vp_FPCamera bob values can not be protected using ObscuredTypes.

Sending an ObscuredType variable across the network in Photon PUN

In the UFPS multiplayer add-on (which uses Photon PUN), if you want to send an RPC with - or serialize - obscured values, you must first cast them to their regular type, like so:

(float)d.CurrentHealth

支持和附加信息(Support and additional information)

That's about it! The file Readme PDF in the root folder of the asset has detailed info on UFPS on the web and how to get in touch with us. Again, big thanks for buying this asset and good luck with your game! =)

© Opsive, All rights reserved.

OpsiveLogoBlack.png

原文