Tweaks to friction constants.
[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 = 3.5;
48 var FRICTIONS = 5.0;
49 var DRAG_FREE = 0.01;
50 var DRAG_OPEN = 5.0;
51 var DRAG_LOCK = 10.0;
52 var CORRECTION = 3.0;
53
54 var leftAngle = (1 - this.leftPivot) * Math.PI / 2;
55 var rightAngle = (1 - this.rightPivot) * Math.PI / 2;
56
57 var vx = this.x - this.lastX;
58 var vy = this.y - this.lastY;
59
60 var cleft = Math.cos(leftAngle);
61 var cright = Math.cos(rightAngle);
62 var sleft = Math.sin(leftAngle);
63 var sright = Math.sin(rightAngle);
64
65 var ax = 0;
66 var ay = GRAVITY;
67
68 var thrust = +!this.free * +this.up * THRUST;
69 ax += thrust * (cleft - cright);
70 ay += thrust * (sright + sleft);
71
72 var drag = this.up ? DRAG_OPEN : this.free ? DRAG_FREE : DRAG_LOCK;
73 ax += drag * Math.max(cleft, cright) * vx * vx * -Math.sign(vx);
74 ay += drag * (sleft + sright) * vy * vy * -Math.sign(vy);
75
76 if (!this.up || this.free)
77 ax += CORRECTION * (cleft - cright) * vy * vy * Math.sign(vy);
78
79 var origX = this.x;
80 var origY = this.y;
81 this.y += vy + ay;
82 var collided = this.y < 0;
83 if (collided) {
84 var friction = -Math.sign(vx) * Math.abs(ay)
85 * (Math.abs(vx) < 0.001 ? FRICTIONS : FRICTIONK);
86 ax += Math.sign(friction) * Math.min(Math.abs(friction), Math.abs(vx));
87 }
88 this.x += vx + ax;
89 this.y = Math.max(0, this.y);
90 this.lastX = origX;
91 this.lastY = origY;
92 this._updateTransforms();
93 },
94
95 TAPS: ['tick'],
96 });
97
98 var GameScene = yT(yuu.Scene, {
99 constructor: function () {
100 yuu.Scene.call(this);
101
102 var zoom = 2;
103 this.layer0.resize(
104 zoom * -1.3333333333/2, zoom * -0.2, zoom * 1.3333333333, zoom * 1);
105
106 var body, left, right;
107 this.player = new yuu.E(body = new yuu.Transform()
108 .setScale([0.081, 0.091, 1]),
109 new yuu.QuadC('@player')
110 .setAnchor('bottom')
111 .setPosition([0, 0]));
112 var leftWing = new yuu.E(left = new yuu.Transform()
113 .setPosition([-0.3, 0.65, 0])
114 .setScale([0.45, 0.22, 1]),
115 new yuu.QuadC('@left')
116 .setZ(-1)
117 .setAnchor("right")
118 .setPosition([0, 0]));
119 var rightWing = new yuu.E(right = new yuu.Transform()
120 .setPosition([0.3, 0.65, 0])
121 .setScale([0.45, 0.22, 1]),
122 new yuu.QuadC('@right')
123 .setZ(-1)
124 .setAnchor('left')
125 .setPosition([0, 0]));
126 this.player.addChildren(leftWing, rightWing);
127 this.entity0.addChild(this.player);
128
129 var ground = new yuu.E(new yuu.Transform()
130 .setPosition([0, -10, 1])
131 .setScale([100, 20, 1]),
132 new yuu.QuadC()
133 .setColor([0, 0.5, 0, 1]));
134 this.entity0.addChild(ground);
135
136 this.player.attach(
137 this.controller = new PlayerController(body, left, right));
138 Object.assign(this.commands, this.controller.commands);
139
140 this.ready = yuu.ready([
141 new yuu.Material('@player'),
142 new yuu.Material('@left'),
143 new yuu.Material('@right')]);
144 },
145
146 init: function () {
147 var audio0 = new Audio();
148 audio0.src = audio0.canPlayType('audio/ogg')
149 ? "data/sound/starting-line.ogg"
150 : "data/sound/starting-line.mp3";
151 audio0.autoplay = true;
152 audio0.loop = true;
153 document.body.appendChild(audio0);
154 var source = yuu.audio.createMediaElementSource(audio0);
155 source.connect(yuu.audio.music);
156 },
157
158 KEYBINDS: {
159 space: '+up',
160 up: '+up',
161 q: '+dleftLeft',
162 w: '+dleftRight',
163 o: '+drightLeft',
164 p: '+drightRight',
165 z: '+free',
166 x: '+up',
167 }
168 });
169
170 function start () {
171 yuu.director.start();
172 }
173
174 function load () {
175 storage = ystorage.getStorage();
176 yuu.audio.storage = storage;
177 var game = new GameScene();
178 yuu.director.pushScene(game);
179 return game.ready;
180 }
181
182 window.addEventListener("load", function() {
183 yuu.registerInitHook(load);
184 yuu.init({ backgroundColor: [0, 0, 0, 1], antialias: false })
185 .then(start);
186 });