[update] Implemented animations for scene transition.

This commit is contained in:
falsycat 2019-10-13 00:00:00 +00:00
parent b94b9f823e
commit 06fc93a2c4
4 changed files with 243 additions and 22 deletions

View File

@ -1,13 +1,20 @@
/// License: MIT
module sj.SelectScene;
import std.math,
std.variant;
import derelict.sfml2.audio;
import gl4d;
import sj.KeyInput,
sj.LobbyWorld,
sj.ProgramSet,
sj.SceneInterface,
sj.TitleScene,
sj.util.Animation,
sj.util.Easing,
sj.util.audio;
///
@ -20,6 +27,9 @@ class SelectScene : SceneInterface {
sound_ = sfSound_create();
soundres_.Load();
first_state_ = new FirstSetupState(this);
status_ = first_state_;
}
~this() {
sfSound_destroy(sound_);
@ -33,13 +43,19 @@ class SelectScene : SceneInterface {
///
void Initialize() {
first_state_.Initialize();
status_ = first_state_;
}
override SceneInterface Update(KeyInput input) {
if (input.up) {
title_scene_.Initialize();
return title_scene_;
}
return this;
SceneInterface next_scene = this;
AbstractSceneState next_state;
status_.Update(input).visit!(
(SceneInterface scene) { next_scene = scene; },
(AbstractSceneState state) { next_state = state; }
);
status_ = next_state;
return next_scene;
}
override void Draw() {
lobby_.Draw();
@ -67,4 +83,111 @@ class SelectScene : SceneInterface {
sfSound* sound_;
SoundResources soundres_;
FirstSetupState first_state_;
AbstractSceneState status_;
}
private abstract class AbstractSceneState {
public:
alias UpdateResult = Algebraic!(AbstractSceneState, SceneInterface);
this(SelectScene owner) {
owner_ = owner;
}
abstract UpdateResult Update(KeyInput input);
@property SelectScene owner() {
return owner_;
}
protected:
static UpdateResult CreateResult(SceneInterface s) {
return UpdateResult(s);
}
static UpdateResult CreateResult(AbstractSceneState s) {
return UpdateResult(s);
}
private:
SelectScene owner_;
}
private class FirstSetupState : AbstractSceneState {
public:
this(SelectScene owner) {
super(owner);
stage_appear_state_ = new StageAppearState(owner);
}
enum AnimeFrames = 30;
enum BgInnerColor = vec4(0.8, 0.6, 0.6, 1);
enum BgOuterColor = vec4(-0.4, -0.4, -0.4, 1);
enum CubeRotationSpeed = vec3(0, PI/10, 0);
enum CubeInterval = 0.06;
void Initialize() {
anime_ = Animation(AnimeFrames);
bg_inner_ease_ = Easing!vec4(owner.lobby_.background.inner_color, BgInnerColor);
bg_outer_ease_ = Easing!vec4(owner.lobby_.background.outer_color, BgOuterColor);
cube_interval_ease_ = Easing!float(owner.lobby_.cube_interval, CubeInterval);
}
override UpdateResult Update(KeyInput input) {
const ratio = anime_.Update();
owner.lobby_.cube_matrix.rotation += CubeRotationSpeed * (ratio+0.2);
owner.lobby_.cube_interval = cube_interval_ease_.Calculate(ratio);
owner.lobby_.background.inner_color = bg_inner_ease_.Calculate(ratio);
owner.lobby_.background.outer_color = bg_outer_ease_.Calculate(ratio);
if (anime_.isFinished) {
stage_appear_state_.Initialize();
return CreateResult(stage_appear_state_);
}
return CreateResult(this);
}
private:
StageAppearState stage_appear_state_;
Animation anime_;
Easing!vec4 bg_inner_ease_;
Easing!vec4 bg_outer_ease_;
Easing!float cube_interval_ease_;
}
private class StageAppearState : AbstractSceneState {
public:
this(SelectScene owner) {
super(owner);
}
enum AnimeFrames = 30;
enum CubeRotationSpeed = vec3(0, PI/500, 0);
void Initialize() { // TODO: pass a stage data
anime_ = Animation(AnimeFrames);
cube_interval_ease_ = Easing!float(owner.lobby_.cube_interval, 0.005);
sfSound_setBuffer(owner.sound_, owner.soundres_.spotlight);
sfSound_play(owner.sound_);
}
override UpdateResult Update(KeyInput input) {
const ratio = anime_.Update();
owner.lobby_.cube_matrix.rotation += CubeRotationSpeed +
(FirstSetupState.CubeRotationSpeed - CubeRotationSpeed) * (1-ratio);
owner.lobby_.cube_interval = cube_interval_ease_.Calculate(ratio);
return CreateResult(this);
}
private:
Animation anime_;
Easing!float cube_interval_ease_;
}

View File

@ -1,7 +1,8 @@
/// License: MIT
module sj.TitleScene;
import std.math;
import std.conv,
std.math;
import gl4d;
@ -10,7 +11,9 @@ import sj.KeyInput,
sj.ProgramSet,
sj.SelectScene,
sj.SceneInterface,
sj.TitleTextProgram;
sj.TitleTextProgram,
sj.util.Animation,
sj.util.Easing;
///
class TitleScene : SceneInterface {
@ -23,10 +26,35 @@ class TitleScene : SceneInterface {
return m;
}();
///
enum AnimationFrame = 30;
///
enum BgInnerColor = vec4(0.9, 0.9, 0.9, 1);
///
enum BgOuterColor = vec4(-0.1, -0.1, -0.1, 1);
///
enum CubeInterval = 0.005;
///
this(LobbyWorld lobby, ProgramSet program) {
lobby_ = lobby;
title_ = program.Get!TitleTextProgram;
lobby_.view.pos = vec3(0, -0.15, -1);
lobby_.view.target = vec3(0, -0.15, 0);
lobby_.view.up = vec3(0, 1, 0);
lobby_.background.inner_color = BgInnerColor;
lobby_.background.outer_color = BgOuterColor;
lobby_.light_pos = vec3(0, 9, -1);
lobby_.cube_material.diffuse_color = vec3(0.1, 0.1, 0.1);
lobby_.cube_material.light_color = vec3(1, 0.8, 0.8);
lobby_.cube_material.light_power = vec3(100, 100, 100);
lobby_.cube_material.ambient_color = vec3(0.2, 0.2, 0.2);
lobby_.cube_material.specular_color = vec3(0.5, 0.2, 0.2);
lobby_.cube_interval = CubeInterval;
}
///
@ -36,25 +64,23 @@ class TitleScene : SceneInterface {
///
void Initialize() {
lobby_.view.pos = vec3(0, -0.15, -1);
lobby_.view.target = vec3(0, -0.15, 0);
lobby_.view.up = vec3(0, 1, 0);
anime_ = Animation(AnimationFrame);
lobby_.background.inner_color = vec4(0.9, 0.9, 0.9, 1);
lobby_.background.outer_color = vec4(-0.1, -0.1, -0.1, 1);
bg_inner_ease_ = Easing!vec4(lobby_.background.inner_color, BgInnerColor);
bg_outer_ease_ = Easing!vec4(lobby_.background.outer_color, BgOuterColor);
lobby_.light_pos = vec3(0, 9, -1);
lobby_.cube_material.diffuse_color = vec3(0.1, 0.1, 0.1);
lobby_.cube_material.light_color = vec3(1, 0.8, 0.8);
lobby_.cube_material.light_power = vec3(100, 100, 100);
lobby_.cube_material.ambient_color = vec3(0.2, 0.2, 0.2);
lobby_.cube_material.specular_color = vec3(0.5, 0.2, 0.2);
frame_ = 0;
cube_interval_ease_ = Easing!float(lobby_.cube_interval, CubeInterval);
}
override SceneInterface Update(KeyInput input) {
const ratio = anime_.Update();
lobby_.cube_matrix.rotation += vec3(PI/600, PI/600, PI/600);
lobby_.background.inner_color = bg_inner_ease_.Calculate(ratio);
lobby_.background.outer_color = bg_outer_ease_.Calculate(ratio);
lobby_.cube_interval = cube_interval_ease_.Calculate(ratio);
if (input.down) {
select_scene_.Initialize();
return select_scene_;
@ -63,7 +89,8 @@ class TitleScene : SceneInterface {
}
override void Draw() {
lobby_.Draw();
title_.Draw(lobby_.Projection, lobby_.view.Create(), TitleMatrix, frame_++);
title_.Draw(lobby_.Projection, lobby_.view.Create(), TitleMatrix,
(anime_.frame%int.max).to!int);
}
private:
@ -73,5 +100,9 @@ class TitleScene : SceneInterface {
TitleTextProgram title_;
int frame_;
Animation anime_;
Easing!vec4 bg_inner_ease_;
Easing!vec4 bg_outer_ease_;
Easing!float cube_interval_ease_;
}

30
src/sj/util/Animation.d Normal file
View File

@ -0,0 +1,30 @@
/// License: MIT
module sj.util.Animation;
import std.algorithm;
///
struct Animation {
public:
///
this(size_t frame_count) {
frame_count_ = frame_count;
}
///
float Update() {
return (frame_++ * 1f / frame_count_).clamp(0f, 1f);
}
///
@property bool isFinished() const {
return frame_ >= frame_count_;
}
///
@property size_t frame() const {
return frame_;
}
private:
size_t frame_count_;
size_t frame_;
}

37
src/sj/util/Easing.d Normal file
View File

@ -0,0 +1,37 @@
/// License: MIT
module sj.util.Easing;
///
enum EasingType {
Linear,
LinearMountain,
}
///
struct Easing(T) {
public:
///
this(T st, T ed, EasingType type = EasingType.Linear) {
st_ = st;
ed_ = ed;
type_ = type;
}
///
T Calculate(float t) {
final switch (type_) with (EasingType) {
case LinearMountain:
t = t*2;
t = t > 1? 2-t: t;
goto case;
case Linear:
return (ed_ - st_) * t + st_;
}
}
private:
T st_;
T ed_;
EasingType type_;
}