Boxing Game

1) File

2) main.js

let ghost = App.loadSpritesheet("ghost.png", 32, 48, {
	left: [2],
	right: [1],
	up: [3],
	down: [0],
});

let redBoxing = App.loadSpritesheet("redBoxing.png");

const STATE_INTRO = 3001;
const STATE_INIT = 3002;
const STATE_RULE = 3003;
const STATE_PLAYING = 3004;
const STATE_JUDGE = 3005;
const STATE_END = 3006;

let lastSurvivor = null;
let _start = false;
let _players = App.players;

let _state = STATE_INIT;
let _stateTimer = 0;

let _alive = 0;

let _widget = null;

function init() {
	for (let i in _players) {
		let p = _players[i];
		setHPgage(p, p.tag.hp);
		p.sendUpdated();
	}
	_alive = checkSuvivors();
}

function startState(state) {
	_state = state;
	_stateTimer = 0;
	switch (_state) {
		case STATE_INTRO:
			for (let i in _players) {
				let p = _players[i];
				if (p.tag.widget) {
					p.tag.widget.destroy();
					p.tag.widget = null;
				}
			}
			// Game starts
			_start = true;
			_widget = App.showWidget("intro.html", "middle", 350, 340);
			App.playSound("intro.wav");
			break;
		case STATE_INIT:
			init();
			break;
		case STATE_RULE:
			_widget = App.showWidget("rule.html", "middle", 400, 200);

			for (let i in _players) {
				let p = _players[i];
				p.moveSpeed = 0;
				p.sendUpdated();
			}
			break;
		case STATE_PLAYING:
			if (_widget) {
				_widget.destroy();
				_widget = null;
			}

			_widget = App.showWidget("status.html", "top", 700, 300);

			for (let i in _players) {
				let p = _players[i];
				p.moveSpeed = 80;
				p.sendUpdated();
			}

			break;
		case STATE_JUDGE:
			break;
		case STATE_END:
			if (_widget) {
				_widget.destroy();
				_widget = null;
			}

			_start = false;

			for (let i in _players) {
				let p = _players[i];
				p.sprite = null;
				p.attackSprite = null;
				p.title = null;
				p.sprite = null;
				p.moveSpeed = 80;
				p.sendUpdated();
			}

			Map.clearAllObjects();
			break;
	}
}

// Functions for displaying HP blocks
function setHPgage(p, hp) {
	switch (hp) {
		case 5:
			p.title = "▮▮▮▮▮";
			break;
		case 4:
			p.title = "▮▮▮▮";
			break;
		case 3:
			p.title = "▮▮▮";
			break;
		case 2:
			p.title = "▮▮";
			break;
		case 1:
			p.title = "▮";
			break;
	}
}

// Functions for checking the number of surviving players
function checkSuvivors() {
	let alive = 0;
	for (let i in _players) {
		let p = _players[i];
		if (p.tag.alive) {
			lastSurvivor = p;
			++alive;
		}
	}
	return alive;
}

App.onStart.Add(function () {
	startState(STATE_INTRO);
});

App.onJoinPlayer.Add(function (p) {
	p.tag = {
		widget: null,
		alive: true,
		hp: 5,
		shield: false,
		time: 1, // Property for setting the invincible status for 1 sec after getting hit
	};

	p.attackSprite = redBoxing;

	// When a new player enters during the game, set the player dead
	if (_start) {
		p.moveSpeed = 5;
		p.sprite = ghost;
		p.tag.alive = false;
		p.sendUpdated();
	}

	_players = App.players;
});

App.onLeavePlayer.Add(function (p) {
	p.attackSprite = null;
	p.title = null;
	p.sprite = null;
	p.moveSpeed = 80;
	p.sendUpdated();

	_players = App.players;
});

// When attacking another player
App.onUnitAttacked.Add(function (sender, x, y, target) {
	if (_state != STATE_PLAYING) return;

	// If the attacker is dead, return
	if (!sender.tag.alive) return;

	// If the target is alive, and "shield" is "false"
	if (target.tag.alive && !target.tag.shield) {
		target.tag.hp--; // Reduce the target's health by 1.

		// When the target's health becomes 0 
		if (target.tag.hp == 0) {
			target.title = null; // Delete title
			target.tag.alive = false; // alive property false
			target.sprite = ghost; // Avatar turn into a ghost
			target.moveSpeed = 5; // moveSpeed 80 -> 5
			target.sendUpdated(); // Update target property

			_alive = checkSuvivors();
			// When there is a single last survivor
			if (_alive == 1) {
				if (_widget) {
					_widget.destroy();
					_widget = null;
				}
				// Show all connected players the result.html widget
				_widget = App.showWidget("result.html", "top", 1055, 500);
				// Send the last survivor's nickname to display in the widget
				_widget.sendMessage({
					alive: _alive,
					name: lastSurvivor.name,
				});

				App.playSound("result.wav");

				_stateTimer = 0;
				startState(STATE_JUDGE);
			}
		} else {
			// Target becomes invincible for 1 sec after getting hit (shield = true)
			target.tag.shield = true;
			setHPgage(target, target.tag.hp);
			target.sendUpdated();
		}
	}
});

App.onUpdate.Add(function (dt) {
	if (!_start) return;

	_stateTimer += dt;
	switch (_state) {
		case STATE_INTRO:
			// Display the intro.html widget for 5 secs and start STATE_INIT
			if (_stateTimer >= 5) {
				if (_widget) {
					_widget.destroy();
					_widget = null;
				}
				App.stopSound();

				startState(STATE_INIT);
			}
			break;
		case STATE_INIT:
			startState(STATE_RULE);
			break;

		// Display the rule.html widget for 3 secs and start STATE_PLAYING
		case STATE_RULE:
			if (_stateTimer >= 3) {
				if (_widget) {
					_widget.destroy();
					_widget = null;
				}
				startState(STATE_PLAYING);
			}
			break;

		case STATE_PLAYING:
			// Update the number of survivors of the status.html widget
			if (_widget) {
				_widget.sendMessage({
					suvivors: _alive,
				});
			}

			for (let i in _players) {
				let p = _players[i];

				// Skip if the player is dead
				if (!p.tag.alive) continue;

				// Shield property becomes false after 1 sec 
				if (p.tag.shield) {
					p.tag.time -= dt;
					if (p.tag.time <= 0) {
						p.tag.shield = false;
						p.tag.time = 1; // Reset shield duration to 1 sec
					}
				}
			}

			_alive = checkSuvivors();

			// Display the result.html widget if the number of a survivor is 1 or 0
			if (_alive == 1) {
				if (_widget) {
					_widget.destroy();
					_widget = null;
				}

				_widget = App.showWidget("result.html", "top", 1055, 500);
				_widget.sendMessage({
					alive: _alive,
					name: lastSurvivor.name,
				});

				App.playSound("result.wav");
				startState(STATE_JUDGE);
			} else if (_alive == 0) {
				if (_widget) {
					_widget.destroy();
					_widget = null;
				}

				_widget = App.showWidget("result.html", "top", 1055, 500);
				_widget.sendMessage({
					alive: _alive,
				});

				App.playSound("result.wav");
				startState(STATE_JUDGE);
			}

			break;
		//Display the result.html widget for 5 secs and start STATE_END
		case STATE_JUDGE:
			if (_stateTimer >= 5) {
				startState(STATE_END);
			}
			break;
		case STATE_END:
			break;
	}
});

// Function executes when the app is closed or the game block is destroyed.
App.onDestroy.Add(function () {
	// Delete all objects installed by the app
	Map.clearAllObjects();
});

Last updated