Race
Last updated
Last updated
1) File
2) main.js
const STATE_INIT = 3000;
const STATE_READY = 3001;
const STATE_PLAYING = 3002;
const STATE_JUDGE = 3004;
const STATE_END = 3005;
const STATE_INTRO = 3006;
let _players = App.players;
let _state = STATE_INIT;
let _start = false;
let _stateTimer = 0;
let _countDown = 10;
let _finishCountDown = false;
let _finishCount = 30;
let _finishTimer = 0;
let _delayTimer = 0;
let _playerBaseSpeed = 120;
let _rank = 1;
let _rankList = [];
// When all players pass the finish line
function finishCheck(){
let allPlayer = 0;
let finishedPlayer = 0;
for(let p of _players){
if(!p)
continue;
if(p.tag.isNotPlayer)
continue;
if(p.tag.isFinish)
finishedPlayer++;
allPlayer++;
}
if(finishedPlayer == allPlayer)
return true
return false;
}
// Check if the race map is normally set; if not, return the error message
function checkSetting(){
let warningMsg = '';
if (!Map.hasLocation("race_start_point")) {
warningMsg = 'race_start_point';
}
if (!Map.hasLocation("race_end_point")) {
warningMsg = 'race_end_point';
}
if (!Map.hasLocation("race_finish_point")) {
warningMsg = 'race_finish_point';
}
return warningMsg;
}
function startState(state){
_state = state;
_stateTimer = 0;
switch (state) {
case STATE_INIT:
for(let p of _players){
//Check the user who started Race app
if(p.id == App.creatorID){
if(p.isMobile)
//Widget for mobile users
p.tag.widget = p.showWidget("setting.html", "bottom", 440, 340);
else
//Widget for desktop users
p.tag.widget = p.showWidget("setting.html", "middle", 440, 340);
p.tag.widget.sendMessage({
str_title : 'Run',
str_title_text1 : "A race to see who reaches the finish line the fastest",
str_title_text2 : 'Click the Start Running button to start the game',
str_title_start : "Start",
str_title_how : "How to set up a map"
});
p.tag.widget.onMessage.Add(function (sender, msg) {
//Delete the displayed widget when quitting the game
if (msg.type == "cancle") {
if(p.tag.widget_warning){
p.tag.widget_warning.destroy();
p.tag.widget_warning = null;
}
if(p.tag.widget){
p.tag.widget.destroy();
p.tag.widget = null;
}
} else {
// Check the necessary settings for the map
let warning = checkSetting();
if(warning !== ''){
if(p.tag.widget_warning){
p.tag.widget_warning.destroy();
p.tag.widget_warning = null;
}
if(p.isMobile)
p.tag.widget_warning = App.showWidget("warning.html", "top", 440, 60);
else
p.tag.widget_warning = App.showWidget("warning.html", "bottom", 440, 250);
p.tag.widget_warning.sendMessage({
str_warningText : 'Race track needs to be set up',
str_warningText2 : ' needed)',
str_warningText3 : 'Run',
warningMsg: warning,
})
} else {
if(p.tag.widget){
p.tag.widget.destroy();
p.tag.widget = null;
}
startState(STATE_INTRO);
_start = true;
}
}
})
}
}
break;
case STATE_INTRO:
App.showCenterLabel("\n minigame - RUN \n\n", 0xffffff, 0x000000, 120); ;
break;
case STATE_READY:
for(let p of _players){
if(p.tag.start)
continue;
//Locate all players to "race_start_point"
p.spawnAtLocation("race_start_point");
p.moveSpeed = 0;
p.sendUpdated();
}
break;
case STATE_PLAYING:
App.showCenterLabel("Start!!", 0xffffff, 0x000000, 120); ;
for(let p of _players){
if(p.tag.start)
continue;
p.moveSpeed = _playerBaseSpeed;
p.sendUpdated();
}
break
// Process the game result
case STATE_JUDGE:
for(let i =0 ; i <_rankList.length; i++){
let rank = '';
if(i == 0)
rank = '1st';
else if(i == 1)
rank = '2nd';
else if(i == 2)
rank = '3rd';
else
rank = `${i + 1}th`;
//Display the ranking when the game ends
App.sayToAll(`${rank} : ${_rankList[i].name} !`);
}
for(let p of _players){
p.moveSpeed = 80;
p.sendUpdated();
}
_start = false;
break
// Process the game end
case STATE_END:
for(let p of _players){
//Spawn all players to "race_end_point" when the game ends
p.spawnAtLocation("race_end_point");
if(p.tag.isNotPlayer)
p.tag.isNotPlayer = false;
}
_start = false;
break
}
}
App.onLeavePlayer.add(function(p){
_players = App.players;
p.moveSpeed = 80;
p.sendUpdated();
})
// Process when a player enters the Space
App.onJoinPlayer.Add(function (p) {
p.tag = {};
//Process when a player enters after the game has started
if (_start) {
p.tag.isNotPlayer = true;
} else {
p.tag.isNotPlayer = false;
p.tag.speedTimer = 0;
p.tag.isFinish = false;
p.tag.speedChnage = false;
p.sendUpdated();
}
//Locate a player who enters after the game has started to "race_end_point"
if(p.tag.isNotPlayer)
p.spawnAtLocation("race_end_point");
_players = App.players;
});
App.onStart.Add(function(){
startState(_state);
//When a player passes through the locations "speed_set_40", "speed_set_60", "speed_set_140", and "speed_set_160"
//its speed becomes the value of the location for 2secs and become normal (_playerBaseSpeed) again
//e.g. passing "speed_set_40" turns the player's speed to 40
let speed = [40,60,140,160];
for(let i =0; i<speed.length; i++){
App.addOnLocationTouched(`speed_set_${speed[i]}`, function(p){
if(_state !== STATE_PLAYING)
return;
p.moveSpeed = speed[i];
p.tag.speedTimer = 0;
p.tag.speedChnage = true;
//A label saying "Speed increased" or "Speed reduced" appears to the player when the speed has changed
let str = '';
if(i == 0)
str = 'Speed greatly reduced';
else if(i == 1)
str = 'Speed reduced';
else if(i == 2)
str = 'Speed increased';
else
str = 'Speed greatly increased';
p.showCenterLabel(`${str}`, 0xffffff, 0x000000, 120);
p.sendUpdated();
})
}
//"speed_set_random" means the player's speed will become one of 40, 60, 140, or 160 in a random way for 2 secs
App.addOnLocationTouched(`speed_set_random`, function(p){
if(_state !== STATE_PLAYING)
return;
p.moveSpeed = speed[Math.floor(Math.random() * 4)];
//A label saying "Speed increased" or "Speed reduced" appears to the player when the speed has changed
let str = '';
if(p.moveSpeed == 40)
str = 'Speed greatly reduced';
else if(p.moveSpeed == 60)
str = 'Speed reduced';
else if(p.moveSpeed == 140)
str = 'Speed increased';
else
str = 'Speed greatly increased';
p.showCenterLabel(`${str}`, 0xffffff, 0x000000, 120);
p.tag.speedTimer = 0;
p.tag.speedChnage = true;
p.sendUpdated();
})
//When a player passes the finish line
App.addOnLocationTouched("race_finish_point", function(p){
if(p.tag.isFinish)
return;
if(p.tag.isNotPlayer)
return;
_delayTimer = 0;
// When the first runner passes the finish line, a 30-second countdown begins
if(!_finishCountDown)
_finishCountDown = true;
// Check if any player passes the finish line first time
p.tag.isFinish = true;
_rankList.push(p);
_rank++;
})
});
App.onUpdate.Add(function(dt){
_stateTimer += dt;
if(_start){
for(let p of _players){
if(p.tag.isNotPlayer)
p.showCenterLabel("game is in progress, please wait..",0xffffff, 0x000000, 120);
}
}
switch (_state) {
case STATE_INIT:
break;
case STATE_INTRO:
if(_stateTimer >= 3){
startState(STATE_READY);
}
break;
case STATE_READY:
//A 10-second countdown begins at the start line
App.showCenterLabel(`${_countDown} seconds later the race will start. `,0xffffff, 0x000000, 120);
if(_stateTimer >= 1){
_stateTimer = 0;
_countDown --;
}
//The race begins when the countdown is over (when "_countDown" becomes 0)
if(_countDown <= 0)
startState(STATE_PLAYING);
break;
case STATE_PLAYING:
for(let p of _players){
if(finishCheck() && _rankList.length == 0){
p.showCenterLabel("There is no winner",0xffffff, 0x000000, 120);
p.spawnAtLocation("race_end_point");
startState(STATE_END);
}
// else if(finishCheck())
// startState(STATE_JUDGE);
if(p.tag.isNotPlayer)
continue;
if(p.tag.speedChnage)
p.tag.speedTimer += dt;
//The speed returns to normal (_playerBaseSpeed) after 2 secs whichever tile players pass
if(p.tag.speedTimer >= 2 && p.tag.speedChnage){
p.moveSpeed = _playerBaseSpeed;
p.tag.speedChnage = false;
p.sendUpdated();
}
}
if(_finishCountDown)
{
_delayTimer += dt;
//When the first player passes the finish line, a label showing the name and a countdown number appears above the player avatar's head
if(_delayTimer <=1.5)
App.showCenterLabel(`${_rankList[_rankList.length -1].name} ${_rank - 1} place ! \n\n ${_finishCount} seconds later the race will end`,0xffffff, 0x000000, 120);
else
App.showCenterLabel(`${_finishCount} seconds later the race will end`,0xffffff, 0x000000, 120);
_finishTimer += dt;
if(_finishTimer >= 1){
_finishCount--;
_finishTimer = 0;
}
// When the countdown is over or every player has finished, move to the next state
if(_finishCount == 0 || finishCheck()){
startState(STATE_JUDGE);
}
}
break;
case STATE_JUDGE:
//A label appears that says who the winner is for 5 sec
if(_stateTimer <= 5){
App.showCenterLabel(`- Winner - \n\n ${_rankList[0].name}`,0xffffff, 0x000000, 120);
}
//A label appears that says "You will soon be transported to the waiting room" for 5 sec
else if(_stateTimer > 5 && _stateTimer <= 10 ){
App.showCenterLabel("You will soon be transported to the waiting room",0xffffff, 0x000000, 120);
}
else {
startState(STATE_END);
}
break;
case STATE_END:
break;
}
});