Skip to content

Instantly share code, notes, and snippets.

@austinmao
Last active December 21, 2016 10:24
Show Gist options
  • Save austinmao/eaec7f1983bfc549ddd1cd7050a71e89 to your computer and use it in GitHub Desktop.
Save austinmao/eaec7f1983bfc549ddd1cd7050a71e89 to your computer and use it in GitHub Desktop.
Unidux + UniRx for character movement
using UnityEngine;
public static class Move {
// specify the possible types of actions
public enum ActionType {
Move,
Stop
}
// actions must have a type and may include a payload
public class Action {
public ActionType actionType;
public Vector2 inputVelocity;
public Transform playerTransform; // curent transform
public Vector3 moveDistance; // movement from current transform
}
// reducers handle state changes
public static class Reducer {
public static State Reduce(State state, Action action) {
switch (action.actionType) {
case ActionType.Move:
state.moving = true;
// store velocity in state
var inputVelocity = state.inputVelocity = action.inputVelocity;
// calculate velocity
var playerTransform = action.playerTransform;
var playerVelocity = (inputVelocity.x * playerTransform.right) + (inputVelocity.y * playerTransform.forward);
// calculate and store moveDistance in state
var moveDistance = state.moveDistance = playerVelocity * Time.fixedDeltaTime;
break;
case ActionType.Stop:
state.moving = false;
break;
}
return state;
}
}
// ActionCreators create actions and deliver payloads
// in redux, you do not dispatch from the ActionCreator to allow
// for easy testability
public static class ActionCreator {
public static Action Move(Vector3 moveDistance) {
// create new action instance
Action action_ = new Action();
// specify required actionType and optional payloads
action_.actionType = ActionType.Move;
// set distance payload
action_.moveDistance = moveDistance;
// return action to the reducer
return action_;
}
public static Action Stop() {
Action action_ = new Action();
action_.actionType = ActionType.Stop;
return action_;
}
}
// BoundActionCreators are helper functions to dispatch action creators
public static class BoundActionCreator {
public static void Move(Vector2 inputVelocity, Transform transform) {
UniduxStore.Instance.Store.Dispatch(ActionCreator.Move(inputVelocity));
}
public static void Stop() {
UniduxStore.Instance.Store.Dispatch(ActionCreator.Stop());
}
}
}
/* Obviously incomplete */
// using UnityEngine;
// using UniRx;
// using UniRx.Triggers;
// using Unidux;
// public class MoveRenderer : MonoBehaviour {
// private State state_ = UniduxStore.Instance.Store.State;
// void Start() {
// renderMove();
// }
// void renderMove(IObservable<Vector2> moveVector) {
// state_.moveDistance.Subscribe(inputVelocity => {
// var playerVelocity = (inputVelocity.x * transform.right) + (inputVelocity.y * transform.forward);
// var distance = playerVelocity * Time.fixedDeltaTime;
// // character.Move(distance);
// Debug.Log($"going to dispatch {distance}");
// Move.BoundActionCreator.Move(distance);
// // UniduxStore.Instance.Store.Dispatch(Move.ActionCreator.Move(distance));
// // TODO: figure out how to dispatch variables
// // UniduxStore.Instance.Store.Dispatch(ActionType, distance);
// })
// .AddTo(this);
// }
// }
using UnityEngine;
using UniRx;
using UniRx.Triggers;
public class PCMoveObserver : MonoBehaviour {
void Start() {
observeAndDispatchInput();
}
void observeAndDispatchInput() {
this.FixedUpdateAsObservable()
// get inputs by axis
.Select(_ => {
var x = Input.GetAxis("Horizontal");
var y = Input.GetAxis("Vertical");
return new Vector2(x, y).normalized;
})
// performance optimization: only dispatch if non-zero movement
.Where(v => v != Vector2.zero)
// dispatch inputVelocity and GameObject transform to move reducer
.Subscribe(inputVelocity => Move.BoundActionCreator.Move(inputVelocity, transform))
// dispose of the observable if GameObject is disposed
.AddTo(this);
}
}
using UnityEngine;
using Unidux;
public class State : StateBase<State>
{
public bool moving { get; set; }
public Vector2 inputVelocity { get; set; }
public Vector3 moveDistance { get; set; }
public override State Clone() {
var state = (State)MemberwiseClone();
return state;
}
}
using Unidux;
using UnityEngine;
public class UniduxStore : SingletonMonoBehaviour<UniduxStore> {
private Store<State> _store;
public Store<State> Store {
get {
if (null == _store) {
_store = new Store<State>(new State());
AddReducers();
}
return _store;
}
}
void Update() {
this.Store.Update();
}
// add all reducers here
void AddReducers() {
_store.AddReducer<Move.Action>(Move.Reducer.Reduce);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment