Module 3 Examples:
Autonomous behaviors
Link to GitHub
Coverage
Concepts
you will explore and understand include
·
The
lerp function: gradual rotation and chasing
·
Simple
implementation of a finite state machine
·
Randomness
and simple examples in games
·
Sprite
sheets and sprite atlas: for efficiency loading and animation
·
Keyframe
and Sprite animation
Unity specific skills you will be exposed and begin learning include
·
Sprite
Editor: extracting individual tiles and sprites
·
Animation
Window: defining keyframe animaitons
·
Animator:
defining animation states, transitions, and, finite state machine
- Gradual Rotation and Chasing
- Run
Behavior:
- WASD: move the egg
- UpArrow chase after the egg
- TurnRate: (be careful, slider bar
may keep focus of mouse, click somewhere else to un-focus)
- 0 does not turn
towards egg
- 1 always point at egg
- 0 < rate < 1: turns
gradually from very slow (values close to 0), to very quick (values
close to 1)
- Egg: WASD_Movement:
trivial behavior
- GreenArrowBehavior:
- Public variables
- TurnRate: connects to the
slider
- Target: connects to
the egg
- PointAtPosition(): function
- Pointing the transform.up towards any
given position
- Incremental rotation
of transform.up to
align with V
- Watch out, if transform.up and V are
pointing in perfect opposite directions, the turning does not work.
- Update()
- Calls PointAtPosition()
- Move in the direction
of transform.up
- In game object movement
consideration
- Easy: Direct control: you
control the position of an object
- Less
Easy:
Indirect control: e.g., you control the velocity of an object
- Obey the
rules of physics: Indirect
control in the world with physics (gravity and potentials for
collisions), you configure the physics to control the object movement
- Follow
your own algorithm:
No control: autonomous (as in this case)
- Learned:
- Gradual rotation: Vector3.lerpUnclamped()
- The PointAtPosition() function
- In-game object
movement considerations
- Autonomous Movement with Randomness:
- Run
Behavior:
- Watch the green arrow
chases the egg, when gets close, egg spawn in a new position in the
pinkish area
- SliderBar changes the pinkish
area size (% of world bound size)
- N-Key: to spawn a new GreenArrow
- H-Key: to hide the egg
- Try: spawn 20 arrows, and
then hide the egg, see a bunch of patrolling arrows?!
- Scene
Setting
- Child: GameManager: empty game object for hanging
the singleton GameManager
- TargetBoundBox (pinkish)
- This box is behind the green arrow (with
larger Z-position values, the larger the Z the more behind).
- Be careful: camera settings only allows z values of up to 1000: MainCamera.Far
- GreenArrow: chases after the egg
- GameManager:
- Awake():
- Initialize must be
done before GreenArrowBehavior::Start()!
- Has reference
- TargetBoundBox: to be scaled into
the size user specified
- TargetBoundSlider: child of UI-Canvas,
the slider bar
- GetTargetBound: computes the
percentage of a given bound. Note the referencing of
- Camera.main: The Camera
component on Main Camera
- orthographicsSize: half of the height
of the world
- orthographicsSize * aspect: half of
the width of the world
- GreenArrowBehavior:
- ComputeNewTargetPosition: a random target
position within a given bound
- Vector.Distance(): Notice this
function, convenient to use
- Learned:
- Compute the percentage
of a given bound (GameManager::GetTargetBound())
- Random position in a
bound (GreenArrow::ComputeNewTargetPosition())
- Distance between two
game objects: Vector3::Distance()
function
- Game object positions:
z values are important
- Front is smaller z,
behind/far is larger z
- SHOULD NOT change the
z-value of an object during game play
- May cause
“flipping” rotation
- E.g., change the z
value of Target to e.g., 1.0f and observe arrow flips
- SliderBar callback function
- Efficient, only
compute when there are changes
- Edited in the UI
- Finite State Machine
- Run
Behavior:
- Move the arrow with
WASD
- Touch the plane to
trigger fixed behavior
- Finite
State Machine:
Simple state on the Plane. Here is the state
transition definition
- Normally, nothing,
when collision
- enlarge for 120 frames
- rotate CW fast for 80
frames
- rotate CCW for 80
frames
- shrink for 120 frames
- return to resting
- Note: in our context, if an
operation does not need time, it is NOT a state. All states, in the FSM
needs more than one update() cycle.
- Implementation
Keys:
- Draw the state
diagram!!
- Instance variables for
state definition and transition
- Enum for individual states
- Case statement in
update()
- State service: Each
state is a separate function!
- As states become
complicated, they can be defined as instance of different classes (with
shared base class)
- Organization
- Partial class
(different files implementing the same class)
- Plane.cs and Plane_FSM.cs
- Each contains
separate details!
- Watch out!! Incomplete
(or unintentional) state specification
- Try moving the GreenUp to touch the Plane when it is changing!!
- E.g., when the plane
has grown large, a new collision will trigger a brand
new state cycle, causing the plane to continue to grow larger!
- What should be done to
avoid? Well, when collide, check if current state is indeed in idle.
- Learned:
- Finite State Machine:
important to
- Draw out ALL states,
and
- Define all possible
input and state transitions
- Implementation key:
review the above!
- Relatively
straightforward to define simple repetitive autonomous behaviors!
- C# Partial class: to help
separate source code into different files for organization
- FSM + Randomness
- Run
Behavior:
- All planes cycles
through states without going into resting
- Random enlarge and
rotation periods (turn constants into variables)
- After a while, look
rather random?
- GameManager: hanging off MainCamera
- Creates all the planes
at startup
- Plane:
- Randomness: in the
Start() function, sets the number of frames in scale/rotate states to be
random
- Learned:
- Beauty and simplicity
of random
§ Ease of expansion when well
abstracted
- Keyframe Animation + FSM
- Disclaimer:
Animation is a large and complex topic, we will only cover the
very basic
- Run Behavior:
- I: to trigger Angry
- D: to trigger size
decrease
- Collide plane and
Arrow: to trigger animation state change from Rest-State
- Arrow: Angry (after
current run, when state is Rest)
- Plane: size decrease
(immediately! Interrupting the state flow)
- Define Animation Clips: results of Keyframe animation: Will
associate an “Animation Time Period” with a game object
- Select a GameObject from the Hierarchy window
- Window->Animation->Animation
(to open the Animation window)
- Create any animation
and you have just associated the defined “Animation Time
Period” with the GameObject
- Create Keyframe
animation:
- Default state: when
“Animation Time Period” is zero
- Click to move the
current-time-line
- Update the GameObject state (e.g., Transform values in the
Scene window
- Click on “Add
Keyframe” (or left-mouse-button->Add Key) to create new keyframe
- Scrub the
current-time-line to see the defined animation
- Note: at the end of
an animation, the animated attribute will always return back to the initial default
value, even if the final state of the animation is different,
they system will automatically return the attribute to the initial
default: animation is a temporary
deviation from the initial default.
- Organized as States in Animator
where transitions between the States define a Finite State Machine for an
object
- Animator (controller):
controls a collection of States
- Tool for organizing
the States as a Finite State Machine: all animations associated with a GameObject (e.g., a character)
- State: in the
Animator as simple wraps of existing Animation
Clips
- Transitions: detailed
support for Transitions between States
- Parameters: can
define to control the states
- Bool: you must turn
on/off yourself
- Trigger: a Bool, if you refer to it to cause state
transition, system will turn it off (refer to Begin)
- Examine:
- Animation State:
control over speed
- State transition:
can be simple conditional (or control in script)
- Example: Here is my example
states (Angry FSM):
- Parameter: Begin a Trigger to cause
transition to IncSize
- Parameter: Dec a Bool (to show how it
works), can be a Trigger
- Sharing: It is possible assign the Angry Animator to any GameObject
- Notice: Arrow and
Plane have the same Angry animator controller
- Exhibits identical
animation from transformation changes
- EXCEPT: with Animation
Event call back, the object needs to have an GreenArrowBehavior
- Scripts:
- ArrowBehavior:
- OnTriggerEnter:
starts Dec animation, and force Plane into DecSize
state
- FromAnimation(): to
receive the event from RotateLeft clip
- PlaneBehavior:
- Defining FromAnimation() DOES NOT help: RotateLeft
calls ArrowBehavior::FromAniamtion().
The binding is with ArrowBehaior!
- Angry State
Behaviors:
- RestState:
monitor keyboard to decide who state to transition to
- DecState:
switch off Dec if true (this can be a Trigger)
- Learned:
- Basic concept of
Keyframe Animation and
- When animation is
defined, an object has a
Animation-Time-Period attribute
- Animation should be
considered as a deviation-cycle form initial value, will always return
back to the initial value
- Unity how to:
- Animation Window (to
create Animation Clips):
create animation clips for a GameObject
- Animator (to create
Finite State Machine)
- Create empty states
and state transitions
- Create and access
parameters to control state and transitions
- Interrupt current
state and force into another state (CrossFade())
- Can share animator
controller (when only controlling transform), if animation events are
defined trickier to share
- Note:
- When the Arrow is in
the Angry cycle, collision response (Another Angry run) will only occurred
AFTER the end! This is contrast with the Plane’s response: via CrossFade(), of going into the response mode immediately.
- It is possible to
create a Finite State Machine with Animator even if there are no
animations involved. I can see both plus (convenient, less coding) and
minus (messy UI workflow, rigid interface). You can decide what you
want to do.
- References:
- Unity manual pages: (how to
use the Editor)
- Unity API pages:
(involve writing scripts)
- Sprite Animation
- Textures in unity: Sprite Mode
- Single (simple image
of an object)
- Multiple (sprite sheet,
sprite atlas): saves load time and/or define animation
- Organization of an
animated spritesheet
- How to slice: Auto
(optimized) vs Fixed Size (for animation support)
- Unity How to: Slicing Sprite Sheet (Atlas)
- Import Sprite Sheet (Type: Sprite (2D and UI))
- Select the Sprite
- Sprite Mode èMultiple
- Invoke the Sprite Editor, Click on Slice è Apply
- You may have to
install the Sprite Editor using PackageManager
- Search for
“2D Sprite” to install under “Unity Registry”
- Run Behavior:
- I – to toggle
Her idle animation
- Transition to idle
is immediate
- Transition from idle
takes a while about 5x idle cycles
- HeroKnight
animation is RICH! (don’t know all of them)
- E: kills the hero
- LMB: attach
- There are much
more!!
- An Example:
- Three spritesheets: HerPlayer, HimPlayer, and TinyTown
- Slice into individual
sprites
- HerPlayer
and HimPlayer by FixedSize
(grid-cell count)
- TinyTown
with Auto detection in size
- Drag individual
sprite to create GameObject with no animation:
drag from TinyTown Tilemap_48 and Tilemap_49
objects are dragged from individual Sprite elements (elements 48 and 49
from TinyTown)
- Drag entire spritesheet to create GameObject
with an Animator: e.g., HerPlayer. (Rename the
create Animator in the Asset window), repeat for HimPlayer
- Share the created
Animator: Unfortunately, this cannot be done! Association with Sprite is
static
- Try it, replace the HimPlayer’s Animator control with Her_Entire_Sheet!
- Painfully created Her_Idle animation clip + state
- Lesson learned: this
stuff is challenging!
- NOT done: if we want
to support interactions, we must define colliders for each of the
sprites! Here is a short tutorial on what you can
do (create associated keyframes for the collider): https://www.youtube.com/watch?v=ls1WxW1zXNc
- Recommendation:
- Learned: some basic Unity how to
- Work with sprite
sheet: slice into individual tiles with Sprite Editor (remember to set
the mode to Multiple)
- Drag to create GameObject with default sprite animation
- Create simple sprite
animation and support animation state transition
- Good animation is
tedious, and more importantly, challenging!
- References:
- Orbiting (rather unrelated
example)
- Run
Behavior
- Eggs orbits around
hero
- No UI support, must
change from the editor, try
- Select Hero in Editor
and move hero around (egg follows)
- Select Egg and change
- Orbit Radius
- Orbit Speed
- Scene:
- Egg is the satellite
- OrbitControlàHostXform points to
Hero’s xform
- OrbitControl.cs on the Egg (can be on
any objects):
- Literally 3-lines of
code!
- Learned:
- Nice to know
quaternion 😊.