d252c7441884e39f2b28026aaf8a0184f8fd3119
[featherfall2.git] / src / main.js
1 "use strict";
2
3 var storage;
4
5 var PlayerController = new yT(yuu.C, {
6 constructor: function (body, left, right) {
7 this.body = body;
8 this.left = left;
9 this.right = right;
10 this.dleftLeft = this.dleftRight =
11 this.drightLeft = this.drightRight = 0;
12 this.up = 0;
13 this.free = 0;
14 this.leftPivot = 0;
15 this.rightPivot = 0;
16 this.x = this.lastX = body.x;
17 this.y = this.lastY = body.y;
18 this.commands = {
19 dleftLeft: yuu.propcmd(this, 'dleftLeft'),
20 dleftRight: yuu.propcmd(this, 'dleftRight'),
21 drightLeft: yuu.propcmd(this, 'drightLeft'),
22 drightRight: yuu.propcmd(this, 'drightRight'),
23 up: yuu.propcmd(this, 'up'),
24 free: yuu.propcmd(this, 'free'),
25 };
26 },
27
28 _updatePivots: function () {
29 var PIVOT_SPEED = 0.05;
30 var leftSpeed = (this.dleftRight - this.dleftLeft) * PIVOT_SPEED;
31 var rightSpeed = (this.drightLeft - this.drightRight) * PIVOT_SPEED;
32 this.leftPivot = yf.clamp(this.leftPivot + leftSpeed, 0, 1);
33 this.rightPivot = yf.clamp(this.rightPivot + rightSpeed, 0, 1);
34 },
35
36 _updateTransforms: function () {
37 this.left.yaw = -this.leftPivot * Math.PI / 2;
38 this.right.yaw = this.rightPivot * Math.PI / 2;
39 this.body.x = this.x;
40 this.body.y = this.y;
41 },
42
43 tick: function () {
44 this._updatePivots();
45 var GRAVITY = -0.0004;
46 var THRUST = 0.00035;
47 var FRICTIONK = 0.6;
48 var FRICTIONS = 2.0;
49 var DRAG_FREE = 0.01;
50 var DRAG_OPEN = 5.0;
51 var DRAG_LOCK = 10.0;
52
53 var leftAngle = (1 - this.leftPivot) * Math.PI / 2;
54 var rightAngle = (1 - this.rightPivot) * Math.PI / 2;
55
56 var vx = this.x - this.lastX;
57 var vy = this.y - this.lastY;
58
59 var cleft = Math.cos(leftAngle);
60 var cright = Math.cos(rightAngle);
61 var sleft = Math.sin(leftAngle);
62 var sright = Math.sin(rightAngle);
63
64 var ax = 0;
65 var ay = GRAVITY;
66
67 var thrust = +!this.free * +this.up * THRUST;
68 ax += thrust * (cleft - cright);
69 ay += thrust * (sright + sleft);
70
71 var drag = this.up ? DRAG_OPEN : this.free ? DRAG_FREE : DRAG_LOCK;
72 ax += drag * Math.max(cleft, cright) * vx * vx * -Math.sign(vx);
73 ay += drag * (sleft + sright) * vy * vy * -Math.sign(vy);
74
75 var origX = this.x;
76 var origY = this.y;
77 this.y += vy + ay;
78 var collided = this.y < 0;
79 if (collided) {
80 var friction = -Math.sign(vx) * Math.abs(ay)
81 * (Math.abs(vx) < 0.001 ? FRICTIONS : FRICTIONK);
82 ax += Math.sign(friction) * Math.min(Math.abs(friction), Math.abs(vx));
83 }
84 this.x += vx + ax;
85 this.y = Math.max(0, this.y);
86 this.lastX = origX;
87 this.lastY = origY;
88 this._updateTransforms();
89 },
90
91 TAPS: ['tick'],
92 });
93
94 var GameScene = yT(yuu.Scene, {
95 constructor: function () {
96 yuu.Scene.call(this);
97
98 var zoom = 2;
99 this.layer0.resize(
100 zoom * -1.3333333333/2, zoom * -0.2, zoom * 1.3333333333, zoom * 1);
101
102 var body, left, right;
103 this.player = new yuu.E(body = new yuu.Transform()
104 .setScale([0.081, 0.091, 1]),
105 new yuu.QuadC('@player')
106 .setAnchor('bottom')
107 .setPosition([0, 0]));
108 var leftWing = new yuu.E(left = new yuu.Transform()
109 .setPosition([-0.3, 0.65, 0])
110 .setScale([0.45, 0.22, 1]),
111 new yuu.QuadC('@left')
112 .setZ(-1)
113 .setAnchor("right")
114 .setPosition([0, 0]));
115 var rightWing = new yuu.E(right = new yuu.Transform()
116 .setPosition([0.3, 0.65, 0])
117 .setScale([0.45, 0.22, 1]),
118 new yuu.QuadC('@right')
119 .setZ(-1)
120 .setAnchor('left')
121 .setPosition([0, 0]));
122 this.player.addChildren(leftWing, rightWing);
123 this.entity0.addChild(this.player);
124
125 var ground = new yuu.E(new yuu.Transform()
126 .setPosition([0, -10, 1])
127 .setScale([100, 20, 1]),
128 new yuu.QuadC()
129 .setColor([0, 0.5, 0, 1]));
130 this.entity0.addChild(ground);
131
132 this.player.attach(
133 this.controller = new PlayerController(body, left, right));
134 Object.assign(this.commands, this.controller.commands);
135
136 this.ready = yuu.ready([
137 new yuu.Material('@player'),
138 new yuu.Material('@left'),
139 new yuu.Material('@right')]);
140 },
141
142 init: function () {
143 var audio0 = new Audio();
144 audio0.src = audio0.canPlayType('audio/ogg')
145 ? "data/sound/starting-line.ogg"
146 : "data/sound/starting-line.mp3";
147 audio0.autoplay = true;
148 audio0.loop = true;
149 document.body.appendChild(audio0);
150 var source = yuu.audio.createMediaElementSource(audio0);
151 source.connect(yuu.audio.music);
152 },
153
154 KEYBINDS: {
155 space: '+up',
156 up: '+up',
157 q: '+dleftLeft',
158 w: '+dleftRight',
159 o: '+drightLeft',
160 p: '+drightRight',
161 z: '+free',
162 x: '+up',
163 }
164 });
165
166 function start () {
167 yuu.director.start();
168 }
169
170 function load () {
171 storage = ystorage.getStorage();
172 yuu.audio.storage = storage;
173 var game = new GameScene();
174 yuu.director.pushScene(game);
175 return game.ready;
176 }
177
178 window.addEventListener("load", function() {
179 yuu.registerInitHook(load);
180 yuu.init({ backgroundColor: [0, 0, 0, 1], antialias: false })
181 .then(start);
182 });