[high fps] Increase input buffer size and fix cloud scroll speed (#3178)

The game stores the last 3 frames of input (50ms of time at 60fps) and
often checks if a button was pressed within those 3 saved frames as a
condition.

When transitioning states, it often checks if some input was received
during the previous state (within those 3 frames) in order to quickly
transition out. A good example of this is when transitioning to
standing, it checks if you can jump this frame and if you had pressed X
recently, and if so, transition immediately to jump. This allows
transitions between states to feel more smooth/forgiving by letting you
jump at a later time when you are transitioning from falling->standing
than if you were only falling.

At 165fps the last 3 frames is only 18ms of time so the input windows
for these smooth transitions are almost 3x shorter.

This PR saves 15 input frames (enough to cover 50ms of time at 300fps)
for each controller and adds a (recently-pressed?) macro that checks all
15 frames. However, it only updates the necessary frames in history
based on the current frame rate. This way, 60fps continues to only check
against 3 input frames, 165fps checks against 9, 240fps checks against
12, and 300fps checks all 15.

---------

Co-authored-by: Tyler Wilding <xtvaser@gmail.com>
This commit is contained in:
Brent Hickey
2024-02-23 15:58:45 -08:00
committed by GitHub
parent d1a6c60eb8
commit 685ff2cf1c
10 changed files with 208 additions and 389 deletions
+95 -3
View File
@@ -152,7 +152,6 @@ The cpad-set-buzz! function can be used for vibration.
)
)
(defmacro cpad-type? (type)
`(= (shr (-> pad status) 4) (cpad-type ,type))
)
@@ -215,7 +214,6 @@ The cpad-set-buzz! function can be used for vibration.
)
)
(defmethod new cpad-list ((allocation symbol) (type-to-make type))
"Create a cpad-list for 2 controllers. It's fine to do this even if one or both controllers
aren't connected yet."
@@ -227,6 +225,36 @@ The cpad-set-buzz! function can be used for vibration.
)
)
;; Allocates enough input frames to support counting 50ms of time at 300fps.
(deftype cpad-history (basic)
((button0-abs pad-buttons 15) ;; bitmask of buttons, pressed or not, with history
(button0-rel pad-buttons 15) ;; bitmask of if button going down.
)
)
;; List of extended history for controllers at high fps. It always has 4 controllers.
(deftype cpad-history-list (basic)
((num-cpads int32)
(cpads cpad-history 4) ;; modified from 2->4 for PC 4-pad support
)
(:methods
(new (symbol type) _type_)
)
)
(defmethod new cpad-history-list ((allocation symbol) (type-to-make type))
"Create a cpad-history-list for 4 controllers. It's fine to do this even if controllers
aren't connected yet. "
(let ((this (object-new allocation type-to-make (the-as int (-> type-to-make size)))))
(set! (-> this num-cpads) 4)
(set! (-> this cpads 0) (new 'global 'cpad-history))
(set! (-> this cpads 1) (new 'global 'cpad-history))
(set! (-> this cpads 2) (new 'global 'cpad-history))
(set! (-> this cpads 3) (new 'global 'cpad-history))
this
)
)
(defun analog-input ((arg0 int) (arg1 float) (arg2 float) (arg3 float) (arg4 float))
"Convert integer input from pad into a float between -out-range and +out-range.
The offset is applied directly to the input.
@@ -311,6 +339,17 @@ The cpad-set-buzz! function can be used for vibration.
;; the two controllers
(define *cpad-list* (new 'global 'cpad-list))
;; the cpad-history for each controller
(define *cpad-history-list* (new 'global 'cpad-history-list))
(desfun generate-frame-checks (pad-idx frames)
(if (= frames 0)
0
`(logior (-> *cpad-history-list* cpads ,pad-idx button0-rel ,(- frames 1))
,(generate-frame-checks pad-idx (- frames 1))
)
)
)
;; weird leftover debug thing, enabling overrides the x position of both sticks on both controllers.
(define *cpad-debug* #f)
@@ -324,7 +363,9 @@ The cpad-set-buzz! function can be used for vibration.
"Read from cpads and update vibration"
(let ((pads *cpad-list*))
(dotimes (i (-> pads num-cpads))
(let ((pad (-> *cpad-list* cpads i)))
(let ((pad (-> *cpad-list* cpads i))
;; og:preserve-this high fps fix
(history (-> *cpad-history-list* cpads i)))
(set! (-> pad old-leftx 1) (-> pad old-leftx 0))
(set! (-> pad old-leftx 0) (-> pad leftx))
(set! (-> pad old-lefty 1) (-> pad old-lefty 0))
@@ -376,6 +417,48 @@ The cpad-set-buzz! function can be used for vibration.
(set! (-> pad button0-abs 1) (-> pad button0-shadow-abs 0))
(set! (-> pad button0-rel 2) (-> pad button0-rel 1))
(set! (-> pad button0-rel 1) (-> pad button0-rel 0))
;; og:preserve-this high fps fix
(when (>= (-> *pc-settings* target-fps) 300)
(set! (-> history button0-abs 14) (-> history button0-abs 13))
(set! (-> history button0-abs 13) (-> history button0-abs 12))
(set! (-> history button0-abs 12) (-> history button0-abs 11))
(set! (-> history button0-rel 14) (-> history button0-rel 13))
(set! (-> history button0-rel 13) (-> history button0-rel 12))
(set! (-> history button0-rel 12) (-> history button0-rel 11))
)
(when (>= (-> *pc-settings* target-fps) 240)
(set! (-> history button0-abs 11) (-> history button0-abs 10))
(set! (-> history button0-abs 10) (-> history button0-abs 9))
(set! (-> history button0-abs 9) (-> history button0-abs 8))
(set! (-> history button0-rel 11) (-> history button0-rel 10))
(set! (-> history button0-rel 10) (-> history button0-rel 9))
(set! (-> history button0-rel 9) (-> history button0-rel 8))
)
(when (>= (-> *pc-settings* target-fps) 165)
(set! (-> history button0-abs 8) (-> history button0-abs 7))
(set! (-> history button0-abs 7) (-> history button0-abs 6))
(set! (-> history button0-abs 6) (-> history button0-abs 5))
(set! (-> history button0-rel 8) (-> history button0-rel 7))
(set! (-> history button0-rel 7) (-> history button0-rel 6))
(set! (-> history button0-rel 6) (-> history button0-rel 5))
)
(when (>= (-> *pc-settings* target-fps) 120)
(set! (-> history button0-abs 5) (-> history button0-abs 4))
(set! (-> history button0-abs 4) (-> history button0-abs 3))
(set! (-> history button0-rel 5) (-> history button0-rel 4))
(set! (-> history button0-rel 4) (-> history button0-rel 3))
)
(when (>= (-> *pc-settings* target-fps) 75)
(set! (-> history button0-abs 3) (-> history button0-abs 2))
(set! (-> history button0-rel 3) (-> history button0-rel 2))
)
(set! (-> history button0-abs 2) (-> history button0-abs 1))
(set! (-> history button0-abs 1) (-> pad button0-shadow-abs 0))
(set! (-> history button0-rel 2) (-> history button0-rel 1))
(set! (-> history button0-rel 1) (-> pad button0-rel 0))
(when (= (-> pad status) 115)
(set! (-> pad abutton 0) (the-as uint (if (logtest? (-> pad button0-abs 0) (pad-buttons right))
255
@@ -515,8 +598,12 @@ The cpad-set-buzz! function can be used for vibration.
)
(set! (-> pad button0-shadow-abs 0) buttons-pushed)
(set! (-> pad button0-abs 0) buttons-pushed)
(set! (-> history button0-abs 0) (-> pad button0-abs 0))
)
(set! (-> pad button0-rel 0) (logclear (-> pad button0-abs 0) (-> pad button0-abs 1)))
(set! (-> history button0-rel 0) (-> pad button0-rel 0))
(when *cpad-debug*
(set! (-> pad leftx) (the-as uint 255))
(set! (-> pad rightx) (the-as uint 255))
@@ -579,6 +666,11 @@ The cpad-set-buzz! function can be used for vibration.
`(logtest? (cpad-pressed ,pad-idx) (pad-buttons ,@buttons))
)
(defmacro recently-pressed? (&key (pad-idx (-> self control cpad number)) &key (frames 15) &rest buttons)
"Checks if a (pad-button) was pressed within the last 50ms, based on frames"
`(logtest? ,(generate-frame-checks pad-idx frames) (pad-buttons ,@buttons))
)
(defmacro cpad-hold? (pad-idx &rest buttons)
`(logtest? (cpad-hold ,pad-idx) (pad-buttons ,@buttons))
)