CSE116的学习笔记-Lec2-5:State_Pattern
State Pattern - More Example
Check the example Jumper below:)
Jumper
2 Player vertical scrolling platform
Screen scrolls up as the players climb the platforms
The bottom of the screen is game over
Goal: Climb faster than the other player
We’ve seen how physics was added to the game
- Platforms / Wall extend StaticObject
- Players extend DynamicObject
- FUlly compatible with the Physics Engine HW
Jumper - Physics
Walls and Platforms extend StaticObject
- Add behavior after collision with player
1 | class JumperObject(location: PhysicsVector, dimensions: PhysicsVector) extends StaticObject(location, dimensions){ |
1 | class Platform(location: PhysicsVector, dimensions: PhysicsVector) extends JumperObject (location, dimensions) { |
1 | class Wall(location: PhysicsVector, dimensions: PhysicsVector) extends JumperObject(location, dimensions) { |
Players extend DynamicObject
- Physics engine applies since all objects in our game are StaticObjects or DynamicObject
- The Player class will set its own velocity based on user inputs
- Velocities are updated by gravity and collisions
- User inputs are effectively the “inended” velocity
- How does the Player set its velocity?
1 | class Player(playerLocation: PhysicsVector, playerDimensions: PhysicsVector) extends DynamicObject(playerLocation, playerDimensions) { |
Jumper - Player
How does the Player set its velocity?
- User inputs
- States! <– Good stuff
Only 3 inputs to control each player
- Left button
- Right button
- Jump button
Player 1:
- a,d,w //wasd 方向键
Player 2: - Left, right, up arrows
Jumper Player Behavior
Each player should:
- Walk left and right when keys are pressed
- Jump when jump is pressed
- Jump higher if walking instead of standing still
- Jump at different heights based on how long the jump button is held after a jump
- Move left and right slower while in the air if the direction is changed
- Jump through platforms while jumping up
- Land on platforms while falling down
- Fall if walked off a ledge
- Block all inputs if the bottom of the screen is reached
We could write all this behavior without the state patten
- Code will likely be hard to follow
- Diffcult to add new features
How to implement these features?
- Write your API
- What methods will change behavior depending on the current state of the object
- These methos define your API ans are declared in the state abstract class
- Decide what states should exist
- Any situation where the behavior is different should be a new state
- Determine the transitions between states
Each player should
- Walk left and right when keys are pressed
- Jump when jump is pressed
- Jump higher if walking instead of standing still
- Jump at different heights based on how long the jump button is held after a jump
- Move left and right slower while in the air if the direction is changed
- Jump throught platforms while jumping up
- Land on platforms while fallin down
- Fall if walked off a ledge
- Block all inputs if the bottom of the screen is reached
API:
- left / right / jump pressed or realeased or released
- 6 methods
- Land on a platform
How to implement these features?
- Decide what stats should exits
States:
- Standing
- Walking
- Jumping / Rising
- Falling
- Dead (Bellow Screen)
State Transitions:
- Standing -> Walking
- left / right pressed
- Walking -> Standing
- left / right pressed
- Walking / Standing -> Jumping
- Jump pressed
- Falling -> Standing
- Land on a platform
- Walking -> Falling
- Walk off a platform
- Jumping -> Falling
- Apex of jump reached
- Any -> GameOver
- Reach the bottom of the screen
Let’s visualize the states and transitions in a state diagram
For each state implement the API methods with the desired havior in that state
- Add default behavior in the state subclass
Use inheritance to limit duplicate code
- Factor out common behavior between states into new class
Adding Functionality
Task: Add a double jumper to Jumper
- How can we add a double jump?
- Players can jump 1 additional time while in the air
- With poor design
- This could be extremely difficult!
- May required modifying a significant amount of existing code
- With our state patetrn
- No Problem at all
- Add functionality to existing states
- Rising and Falling states now react to the jump button by jumping again (Set velocity.z to the jump velocity)
- We’ll add new states
- RisingAfterDoubleJump / FallingAfterDoubleJump
- Extend Rising / Falling resprectively
- Override the jump button press to do nothing
- Update state transitions
- Pree jump from Rising / Falling transitions to the resprective AfterDoubleJump state
- Reaching the apex in RisingAfterDoubleJump transitions to FallingAfterDoubleJump (Not Falling)
- This task could have been completed with a boolean flag instead of using new states
- If this approach is used for many features the code will be harder to maintian
- More to the point: What if your professor says you can’t use control flow, but you have a situation where a button should only work once?
- Try adding more states
1 | var usedDoubleJump = false |
Lecture Question
Question:
- Simulate a TV without using control flow (ie. Use the state pattern)
- In a package named oop.tv, create a Class named TV with no constructor parameters
- The TV class must contain the following methods as its API:
- volumeUp(): Unit
- volumeDown(): Unit
- mute(): Unit power(): Unit
- currentVolume(): Int
- In the tests package, write a test suite named TestTV that will test all the functionality on the spec sheet
- Note: Only call the API methods while testing. Other methods/ variables you create will not exist in the grader submissions
TV Spec Sheet
- TV is initially off when created
- Initial volume is 5
- When the TV is off:
- Volume up/down and mute buttons do nothing
- Current volume is 0
- The power button turns the TV on/off
- Volume up button increases volume by 1 up to a maximum volume of 10
- Volume down button decreases volume by 1 down to minimum volume of 0
- Pressing the mute button mutes the TV
- When the TV is muted:
- Current volume is 0
- Pressing the mute, volume up, or volume down buttons will unmute the TV and restore the volume to the pre- mute volume (Do not in/decrease the volume)
- When turning the TV back on, the volume should return to its value when the TV was last on
- When the TV is first turned on the volume will be 5
- If the TV was turned off while muted, when it is turned back on it should not be muted