-
Notifications
You must be signed in to change notification settings - Fork 115
/
main.js
161 lines (149 loc) · 7.08 KB
/
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/**
* This is the main script which executes the game.
* General explanations for the all source code files of the game are following.
*
********************************************************************************************************************
* This web version of the Pikachu Volleyball is made by
* reverse engineering the core part of the original Pikachu Volleyball game
* which is developed by "1997 (C) SACHI SOFT / SAWAYAKAN Programmers" & "1997 (C) Satoshi Takenouchi".
*
* "physics.js", "cloud_and_wave.js", and some codes in "view.js" are the results of this reverse engineering.
* Refer to the comments in each file for the machine code addresses of the original functions.
********************************************************************************************************************
*
* This web version game is mainly composed of three parts which follows MVC pattern.
* 1) "physics.js" (Model): The physics engine which takes charge of the dynamics of the ball and the players (Pikachus).
* It is gained by reverse engineering the machine code of the original game.
* 2) "view.js" (View): The rendering part of the game which depends on pixi.js (https://www.pixijs.com/, https://github.com/pixijs/pixi.js) library.
* Some codes in this part is gained by reverse engineering the original machine code.
* 3) "pikavolley.js" (Controller): Make the game work by controlling the Model and the View according to the user input.
*
* And explanations for other source files are below.
* - "cloud_and_wave.js": This is also a Model part which takes charge of the clouds and wave motion in the game. Of course, it is also rendered by "view.js".
* It is also gained by reverse engineering the original machine code.
* - "keyboard.js": Support the Controller("pikavolley.js") to get a user input via keyboard.
* - "audio.js": The game audio or sounds. It depends on pixi-sound (https://github.com/pixijs/pixi-sound) library.
* - "rand.js": For the random function used in the Models ("physics.js", "cloud_and_wave.js").
* - "assets_path.js": For the assets (image files, sound files) locations.
* - "ui.js": For the user interface (menu bar, buttons etc.) of the html page.
*/
'use strict';
import { settings } from '@pixi/settings';
import { SCALE_MODES } from '@pixi/constants';
import { Renderer, BatchRenderer, autoDetectRenderer } from '@pixi/core';
import { Prepare } from '@pixi/prepare';
import { Container } from '@pixi/display';
import { Loader } from '@pixi/loaders';
import { SpritesheetLoader } from '@pixi/spritesheet';
import { Ticker } from '@pixi/ticker';
import { CanvasRenderer } from '@pixi/canvas-renderer';
import { CanvasSpriteRenderer } from '@pixi/canvas-sprite';
import { CanvasPrepare } from '@pixi/canvas-prepare';
import '@pixi/canvas-display';
import { PikachuVolleyball } from './pikavolley.js';
import { ASSETS_PATH } from './assets_path.js';
import { setUpUI } from './ui.js';
// Reference for how to use Renderer.registerPlugin:
// https://github.com/pixijs/pixijs/blob/af3c0c6bb15aeb1049178c972e4a14bb4cabfce4/bundles/pixi.js/src/index.ts#L27-L34
Renderer.registerPlugin('prepare', Prepare);
Renderer.registerPlugin('batch', BatchRenderer);
// Reference for how to use CanvasRenderer.registerPlugin:
// https://github.com/pixijs/pixijs/blob/af3c0c6bb15aeb1049178c972e4a14bb4cabfce4/bundles/pixi.js-legacy/src/index.ts#L13-L19
CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
CanvasRenderer.registerPlugin('sprite', CanvasSpriteRenderer);
Loader.registerPlugin(SpritesheetLoader);
// Set settings.RESOLUTION to 2 instead of 1 to make the game screen do not look
// much blurry in case of the image rendering mode of 'image-rendering: auto',
// which is like bilinear interpolation, which is used in "soft" game graphic option.
settings.RESOLUTION = 2;
settings.SCALE_MODE = SCALE_MODES.NEAREST;
settings.ROUND_PIXELS = true;
const renderer = autoDetectRenderer({
width: 432,
height: 304,
antialias: false,
backgroundColor: 0x000000,
backgroundAlpha: 1,
// Decided to use only Canvas for compatibility reason. One player had reported that
// on their browser, where pixi chooses to use WebGL renderer, the graphics are not fine.
// And the issue had been fixed by using Canvas renderer. And also for the sake of testing,
// it is more comfortable just to stick with Canvas renderer so that it is unnecessary to switch
// between WebGL renderer and Canvas renderer.
forceCanvas: true,
});
const stage = new Container();
const ticker = new Ticker();
const loader = new Loader();
renderer.view.setAttribute('id', 'game-canvas');
document.getElementById('game-canvas-container').appendChild(renderer.view);
renderer.render(stage); // To make the initial canvas painting stable in the Firefox browser.
loader.add(ASSETS_PATH.SPRITE_SHEET);
for (const prop in ASSETS_PATH.SOUNDS) {
loader.add(ASSETS_PATH.SOUNDS[prop]);
}
setUpInitialUI();
/**
* Set up the initial UI.
*/
function setUpInitialUI() {
const loadingBox = document.getElementById('loading-box');
const progressBar = document.getElementById('progress-bar');
loader.onProgress.add(() => {
progressBar.style.width = `${loader.progress}%`;
});
loader.onComplete.add(() => {
loadingBox.classList.add('hidden');
});
const aboutBox = document.getElementById('about-box');
const aboutBtn = document.getElementById('about-btn');
const closeAboutBtn = document.getElementById('close-about-btn');
const gameDropdownBtn = document.getElementById('game-dropdown-btn');
const optionsDropdownBtn = document.getElementById('options-dropdown-btn');
// @ts-ignore
gameDropdownBtn.disabled = true;
// @ts-ignore
optionsDropdownBtn.disabled = true;
const closeAboutBox = () => {
if (!aboutBox.classList.contains('hidden')) {
aboutBox.classList.add('hidden');
// @ts-ignore
aboutBtn.disabled = true;
}
aboutBtn.getElementsByClassName('text-play')[0].classList.add('hidden');
aboutBtn.getElementsByClassName('text-about')[0].classList.remove('hidden');
aboutBtn.classList.remove('glow');
closeAboutBtn
.getElementsByClassName('text-play')[0]
.classList.add('hidden');
closeAboutBtn
.getElementsByClassName('text-close')[0]
.classList.remove('hidden');
closeAboutBtn.classList.remove('glow');
loader.load(setup); // setup is called after loader finishes loading
loadingBox.classList.remove('hidden');
aboutBtn.removeEventListener('click', closeAboutBox);
closeAboutBtn.removeEventListener('click', closeAboutBox);
};
aboutBtn.addEventListener('click', closeAboutBox);
closeAboutBtn.addEventListener('click', closeAboutBox);
}
/**
* Set up the game and the full UI, and start the game.
*/
function setup() {
const pikaVolley = new PikachuVolleyball(stage, loader.resources);
setUpUI(pikaVolley, ticker);
start(pikaVolley);
}
/**
* Start the game.
* @param {PikachuVolleyball} pikaVolley
*/
function start(pikaVolley) {
ticker.maxFPS = pikaVolley.normalFPS;
ticker.add(() => {
pikaVolley.gameLoop();
renderer.render(stage);
});
ticker.start();
}