SUPERPOWERS TUTORIAL #4
SUPER ASTEROIDS and SUPER SPACEWAR, Chapter 12
Complete Game Source Reference
Game structure
- Global (script)
- Game (folder)
- Scene (scene)
- Game (script)
- Menu (folder)
- Scene (scene)
- Menu (script)
- Screens (folder)
- Main (folder)
- Sprite (sprite)
- Asteroids (folder)
- Sprite (sprite)
- Spacewar (folder)
- Sprite (sprite)
- GameOver (folder)
- Sprite (sprite)
- Main (folder)
- Button (folder)
- Sprite (sprite)
- Background (folder)
- Background (script)
- Sprite (sprite)
- Ship (folder)
- Ship (script)
- Missile (folder)
- Missile (script)
- Boost (folder)
- Sprite (sprite)
- 0 (folder)
- Model (3D model)
- Prefab (scene)
- Life (folder)
- Sprite (sprite)
- Missile (folder)
- Prefab (scene)
- Sprite (sprite)
- Explosion (folder)
- Sprite (sprite)
- 1 (folder)
- Model (3D model)
- Prefab (scene)
- Life (folder)
- Sprite (sprite)
- Missile (folder)
- Prefab (scene)
- Sprite (sprite)
- Explosion (folder)
- Sprite (sprite)
- Alien (folder)
- Alien (script)
- Model (3D model)
- Prefab (scene)
- Missile (folder)
- Missile (script)
- Prefab (scene)
- Sprite (sprite)
- Life (folder)
- Sprite (sprite)
- Explosion (folder)
- Sprite (sprite)
- Asteroid (folder)
- Asteroid (script)
- Model (3D model)
- Prefab (scene)
- Explosion (folder)
- Sprite (sprite)
- Sounds
- music
- shipShot
- alienShot
- explosion
- shotContact
- Font
Source assets
You can see the repository of this assets here.
- alien
- alien.blend
- alien.obj
- alienExplosion.png
- alienLife.png
- alienMissile.png
- alienTexture.png
- asteroid
- asteroid.blend
- asteroid.obj
- asteroidExplosion.png
- asteroidTexture.png
- castle
- // will be updated
- menu
- asteroids.png
- button.png
- gameover.png
- main.png
- spacewar.png
- scripts
- Alien.ts
- Asteroids.ts
- Background.ts
- Game.ts
- Global.ts
- Menu.ts
- Missile.ts (Alien)
- Missile.ts (Ship)
- Ship.ts
- ships
- boost.png
- ship.blend
- ship.obj
- ship1explosion.png
- ship1life.png
- ship1missile.png
- ship1texture.png
- ship2explosion.png
- ship2life.png
- ship2missile.png
- ship2texture.png
- sounds
- alienShot.mp3
- explosion.mp3
- music.mp3
- shipShot.mp3
- shotContact.mp3
- background.png
- font.png
Source code
Global.ts
// SUPER ASTEROIDS and SUPER SPACEWAR
// Tutorial #4 Game Development with Superpowers
// Main game datas and functions
namespace Game{
// Game timer max value
export const timeMax: number = 7200; //7200 2 minutes
// The game index of the current played game, 0 for Asteroids, 1 for Spacewar
export let nameIndex: number = 0; // Temporary allocation
// The screen limits in width and height + outside border
export let bounds : {
width:number,
height:number
}
// set an invisible border of 2 x 1.5 units (24 pixels wide) around the screen
let border: number = 3;
// Game points won when target shot
export enum points {
asteroidBig = 10,
asteroidMedium = 15,
asteroidSmall = 20,
alien = 50,
ship = 100 ,
death = -50,
}
// Life hearts positions
export const hearts = [
["empty", "empty", "empty", "empty", "empty"],
["full", "empty", "empty", "empty", "empty"],
["full", "full", "empty", "empty", "empty"],
["full", "full", "full", "empty", "empty"],
["full", "full", "full", "full", "empty"],
["full", "full", "full", "full", "full"]
]
// Flags to check HUD changes
export var checkLifeHUD: boolean;
export var checkScoreHUD: boolean;
// Start the game
export function start(){
// Load Game Scene
Sup.loadScene("Game/Scene");
// Set new asteroids list
Asteroids.list = [];
// Set asteroids number to 0
Asteroids.currentCount = 0;
// Set new Ships.missiles list
Ships.missiles = [[], []];
// Set new Alien.missiles list
Alien.missiles = [];
// get the Camera actor the the game Scene
let screen = Sup.getActor("Camera").camera;
// We get the game screen bounds and add the invisible border
bounds = {
width: screen.getOrthographicScale() + border,
height: screen.getOrthographicScale() + border
}
// If the game is Asteroids, load the Ship 1 only
if (nameIndex === 0) {
// Set ship 1 in game
setShip(Ships.index.ship1);
// Set visible false the HUD display for ship 2
Sup.getActor("HUD").getChild("UIShip2").setVisible(false);
// Set visible true the HUD display for alien
Sup.getActor("HUD").getChild("UIAlien").setVisible(true);
// Set Timer HUD visible false
Sup.getActor("HUD").getChild("Timer").setVisible(true);
}
// If the game is Spacewar, load two ships
if (nameIndex === 1) {
// Set ship 1 in game
setShip(Ships.index.ship1);
// Set ship 2 in game
setShip(Ships.index.ship2);
// Set visible true the HUD display for ship 2
Sup.getActor("HUD").getChild("UIShip2").setVisible(true);
// Set visible false the HUD display for alien
Sup.getActor("HUD").getChild("UIAlien").setVisible(false);
// Set Timer HUD visible false
Sup.getActor("HUD").getChild("Timer").setVisible(false);
}
}
function setShip(shipIndex:number){
// Initialize a new variable of type Sup.Actor
let Ship: Sup.Actor;
// Add the ship 1 or 2 to game scene depending the index
if (shipIndex === 0) {
// Create Ship and set the ship variable with the Ship1 actor
Ship = Sup.appendScene("Ship/0/Prefab")[0];
}
else {
// Create Ship and set the ship variable with the Ship2 actor
Ship = Sup.appendScene("Ship/1/Prefab")[0];
}
// Set behavior variables
Ship.getBehavior(ShipBehavior).index = shipIndex;
// Set spawn position of the ship accordingly to the game an ship index
// If game is Asteroids, set position to center
if (nameIndex === 0) {
Ship.setLocalPosition(Ships.spawns[0]);
}
// If game is Spacewar and Ship is 1, set position to corner down left
else if (shipIndex === 0) {
Ship.setLocalPosition(Ships.spawns[1]);
}
// Else it is Ship 2, set position to corner up right
else {
Ship.setLocalPosition(Ships.spawns[2]);
}
}
// Create an alien in the Game scene
export function spawnAlien(){
// Load the alien prefab and get the Alien actor (index 0) as a new alien variable
let alien = Sup.appendScene("Alien/Prefab")[0];
// Choose a random position somewhere at the vertical edges of the game screen
// Create the three axis positions x, y, z
let x: number = 0, y: number = 0, z: number = 0;
// Choose randomly a position on one of the vertical edges
x = Sup.Math.Random.sample([-bounds.width / 2, bounds.width / 2]);
// Get the height without the invisible border
let height = bounds.height - border
// Choose randomly a position on y axis
y = Sup.Math.Random.integer(-height / 2 , height / 2);
// Get alien default Z position
z = Alien.zPosition;
// Set the randomly chosen position to the Alien actor
alien.setLocalPosition(x, y, z);
}
// Create an asteroid in the Game scene
export function spawnAsteroid(){
// Load the asteroid prefab and get the Asteroid actor (index 0) as a new asteroid variable
let asteroid = Sup.appendScene("Asteroid/Prefab")[0];
// Choose a random position somewhere at the edges of the game screen
// Create the three axis positions x, y, z
let x: number = 0, y: number = 0, z: number = 0;
// Choose randomly if the asteroids come from the horizontal or vertical edges
if(Sup.Math.Random.sample([0, 1]) === 0){
x = Sup.Math.Random.sample([-bounds.width / 2, bounds.width / 2]);
y = Sup.Math.Random.integer(-bounds.height / 2, bounds.height / 2);
}
else {
x = Sup.Math.Random.integer(-bounds.height / 2, bounds.height / 2);
y = Sup.Math.Random.sample([-bounds.width / 2, bounds.width / 2]);
}
// Choose randomly the z position on the scene in the range of Asteroids.zPoistions
z = Sup.Math.Random.integer(Asteroids.zPositions.min, Asteroids.zPositions.max);
// Set the randomly chosen position to the Asteroid actor
asteroid.setLocalPosition(x, y, z);
// Report the asteroid size
asteroid.getBehavior(AsteroidBehavior).sizeClass = "big";
}
export function checkCollisionMissile(actor: Sup.Actor, actorList: Sup.Actor[], amplitude: number){
/*
We get the distance between actor and all the actors of the actorList
If the distance if inferior to the amplitude box around the Actor, there is a collision
*/
// Get the position 1 of the actor we check collision with actorList
let position1: Sup.Math.Vector2 = actor.getLocalPosition().toVector2();
// Loop through the actors of listToCheck and check if ....
for(let i = 0; i < actorList.length; i++){
// Get the position 2 of the current actor of the loop inside actorList
let position2: Sup.Math.Vector2 = actorList[i].getLocalPosition().toVector2();
// Get the distance between position 1 and position 2
let distance: number = Math.round(position1.distanceTo(position2)*100)/100;
// If the distance is inferior to the amplitude (collision radius), then it is a collision
if (distance < amplitude) {
// The current actor of the actorList is destroyed
actorList[i].destroy();
// Return true to the behavior which check for collision
return true;
}
}
// Return false to the behavior which check for collision
return false;
}
export function checkCollisionAsteroids(ship: Sup.Actor, shipAmplitude: number) {
/*
Get the distance between the ship and the asteroids, compare the distance with the biggest amplitude
*/
// Initialize a variable asteroid which will take all the asteroids of the list as value
let asteroid: Sup.Actor;
// Get the current position of the ship
let shipPosition: Sup.Math.Vector2 = ship.getLocalPosition().toVector2();
// Loop through all the asteroids in game
for(asteroid of Asteroids.list){
// Get the amplitude of the current asteroid
let asteroidAmplitude: number = asteroid.getBehavior(AsteroidBehavior).amplitude;
// Get the position of the current asteroid
let asteroidPosition: Sup.Math.Vector2 = asteroid.getLocalPosition().toVector2();
// Convert to distance between ship and current asteroid positions
let distance: number = Math.round(shipPosition.distanceTo(asteroidPosition)*100)/100;
// Check if distance is less than the biggest amplitude
if (distance < shipAmplitude || distance < asteroidAmplitude) {
// Destroy the current asteroid
asteroid.getBehavior(AsteroidBehavior).die();
// Return true, the ship is destroyed too
return true;
}
}
return false;
}
// Check collision between actor1 and actor2
export function checkCollisionShip(actor1: Sup.Actor, actor1Amplitude: number) {
// Initialize variable for the actors
let actor2: Sup.Actor;
let actor1Position: Sup.Math.Vector2;
let actor2Position: Sup.Math.Vector2;
let actor2Amplitude: number;
let actor2Alive: boolean;
// If the actor1 is the Ship1, then we check the Ship2 as actor2
if (actor1.getName() === "Ship1"){
actor2 = Sup.getActor("Ship2");
}
// Else, if the actor1 is Ship2 or Alien Ship, we check the Ship1 as actor2
else {
actor2 = Sup.getActor("Ship1");
}
// Get the positions of both actors
actor2Position = actor2.getLocalPosition().toVector2();
actor1Position = actor1.getLocalPosition().toVector2();
// Get amplitud of actor 2
actor2Amplitude = Ships.amplitude;
// Get the life status of the actor 2
actor2Alive = actor2.getBehavior(ShipBehavior).alive;
// Get the distance between the two actors
let distance: number = Math.round(actor1Position.distanceTo(actor2Position)*100)/100;
// To avoid to collide when ship is blinking with invulnerability, return false the collisionChecking if actor 2 not alive
if(!actor2Alive){
return false;
}
// Check if distance if less than the biggest amplitude (or collision radius)
if (distance < actor1Amplitude || distance < actor2Amplitude) {
// Destroy the current asteroid
actor2.getBehavior(ShipBehavior).die();
// Return true, both actor are destroyed
return true;
}
// If condition not met, return false
return false
}
// Update HUD timer in the Game scene
export function updateTimer(time: number){
// Sup.log("one second (60 frames) of", time, "frame left."); // Debug log
// We convert frames in minutes and seconds
let minutes = Math.floor((time / 60) / 60);
let seconds = Math.floor((time / 60) % 60);
// We get The Timer actor from the Game scene and we update the text Renderer with the new time
let timer = Sup.getActor("HUD").getChild("Timer");
// For the last 10 seconds we need to add a 0 to keep 2 numbers in the timer
if (seconds < 10) {
timer.textRenderer.setText(minutes + ":0" + seconds);
}
else {
timer.textRenderer.setText(minutes + ":" + seconds);
}
}
// Add points to the ship score
export function addPoints(ship1: boolean, points: number){
// If ship1 is true, add points to ship1
if(ship1){
Sup.getActor("Ship1").getBehavior(ShipBehavior).score += points;
}
// If ship1 is false, add points to ship2
else {
Sup.getActor("Ship2").getBehavior(ShipBehavior).score += points;
}
}
// Update the score HUD with the score for ship 1 or optionally for ship2
export function updateHUDScore(score1:number, score2?:number) {
// Change the score text displayed on HUD with the new score
Sup.getActor("HUD").getChild("UIShip1").getChild("Score").textRenderer.setText(score1);
// If there is a score 2, do the same for the HUD of ship 1 and ship 2
if(score2){
Sup.getActor("HUD").getChild("UIShip1").getChild("Score").textRenderer.setText(score1);
Sup.getActor("HUD").getChild("UIShip2").getChild("Score").textRenderer.setText(score2);
}
// Set flag to false
Game.checkScoreHUD = false;
}
// Update the life HUD
export function updateHUDLife(life1:number, life2:number){
/*
Explanation of life
*/
// If the game is Asteroids
if (Game.nameIndex === 0){
// Update the player Ship life
for (let i = 0; i < Ships.startLife; i++) {
let heart = Sup.getActor("HUD").getChild("UIShip1").getChild("Life").getChild(i.toString());
heart.spriteRenderer.setAnimation(hearts[life1][i]);
}
// Update the alien life
for (let i = 0; i < Alien.startLife; i++) {
let heart = Sup.getActor("HUD").getChild("UIAlien").getChild(i.toString());
heart.spriteRenderer.setAnimation(hearts[life2][i]);
}
}
if (Game.nameIndex === 1){
// player1 life
for (let i = 0; i < Ships.startLife; i++) {
let heart = Sup.getActor("HUD").getChild("UIShip1").getChild("Life").getChild(i.toString());
heart.spriteRenderer.setAnimation(hearts[life1][i]);
}
// player2 life
for (let i = 0; i < Ships.startLife; i++) {
let heart = Sup.getActor("HUD").getChild("UIShip2").getChild("Life").getChild(i.toString());
heart.spriteRenderer.setAnimation(hearts[life2][i]);
}
}
// Set false to flag checkLifeHUD
Game.checkLifeHUD = false;
}
// Load the gameOver screen and display score
export function gameOver(winner: string){
// Initialize variables
let score1: number;
let score2: number;
// Store the ship1 score before to leave the scene
score1 = Sup.getActor("Ship1").getBehavior(ShipBehavior).score;
// If the game is spacewar, stock also the Ship2 score
if (nameIndex === 1) {
score2 = Sup.getActor("Ship2").getBehavior(ShipBehavior).score;
}
// Close game scene and load menu scene
Sup.loadScene("Menu/Scene");
// Set game over Screen
Sup.getActor("Menu").getBehavior(MenuBehavior).setScreen(Menu.screens.gameover);
// Get in a variable gameOverScreen the gameover screen actor
let gameOverScreen = Sup.getActor("Screens").getChild(Menu.screens.gameover.toString());
// Set the Sprite from the actor to display the winner frame
gameOverScreen.spriteRenderer.setAnimation(winner);
// Display Score
// Set title visible false
Sup.getActor("Title").setVisible(false);
// Get the Score actor in a variable
let score: Sup.Actor = Sup.getActor("Score");
// Set the Score actor visible
score.setVisible(true);
// Set the score text to the current score of ship1
score.getChild("Ship1").textRenderer.setText("Ship1:"+score1);
// If the game is spacewar
if (nameIndex === 1) {
// Set visible true the score of Ship2
score.getChild("Ship2").setVisible(true);
// Set the score text to the current score of ship2
score.getChild("Ship2").textRenderer.setText("Ship2:"+score2);
}
else {
// Set visible false the ship2 score
score.getChild("Ship2").setVisible(false);
}
}
}
// Menu datas
namespace Menu{
// Different menu screen index
export const screens = {
main : "Main",
asteroids : "Asteroids",
spacewar : "Spacewar",
gameover : "GameOver",
}
// Game names index
export enum names {
Asteroids = 0,
Spacewar = 1,
}
}
// Ship datas
namespace Ships{
// Default ship size
export const size: number = 0.5;
// Default ship collision radius
export const amplitude: number = 1.5;
// Starting ship score
export const startScore: number = 0;
// Starting ship life
export const startLife: number = 3;
// Starting spawn positions
export const spawns: Sup.Math.Vector3[] = [
new Sup.Math.Vector3(0, 0, 14), // ship1 for asteroids game
new Sup.Math.Vector3(-4, -12, 2), // ship1 for spacewar game
new Sup.Math.Vector3(4, 12, 4) // ship1 for spacewar game
]
// ship index
export enum index {
ship1 = 0,
ship2 = 1
};
// Starting time before next shoot
export const shootingTimer: number = 30;
// Starting time before respawn
export const respawnTimer: number = 180;
// Starting time before vulnerability
export const invincibleTimer: number = 200;
// Linear speed
export const linearAcceleration: number = 0.005;
// Linear slowing down
export const linearDamping: number = 0.97;
// Rotation speed
export const angularAcceleration: number = 0.02;
// Rotation slowing down
export const angularDamping: number = 0.75;
// Commands for each ship by index
export const commands = [
{left:"LEFT", right:"RIGHT", forward:"UP", shoot:"CONTROL", boost:"SHIFT"}, // commands[0]
{left:"A", right:"D", forward:"W", shoot:"SPACE", boost:"C"} // commands[1]
];
// Missiles list for each ship by index
export let missiles: Sup.Actor[][];
// Starting missile life before destruction (frames)
export const missileLife: number = 60;
// Missile speed (unit/frame)
export const missileSpeed: number = 0.30;
}
// Alien datas
namespace Alien{
// Flag for alien alive
export let alive: boolean = true;
// Starting alien life
export const startLife: number = 5;
// Current alien life
export let lifes: number;
// Alien z position
export const zPosition: number = 12;
// Different alien sizes
export const sizes: number[] = [1.7, 1.3, 1];
// Different collision amplitude related to size
export const amplitudes: number[] = [2.5, 2.2, 2];
// Linear and rotation speed of alien ship
export let linearSpeed: number = 0.05;
export let rotationSpeed: number = 0.01;
// Starting time before alien ship respawn
export const respawnTime: number = 300;
// Current time befer alien ship respawn
export let spawnTimer: number = 0;
// Starting time before alien ship shoot again
export const shootTime: number = 200;
// Alien missile list
export let missiles: Sup.Actor[];
// Alien missile speed (unit/frame)
export const missileSpeed: number = 0.05;
}
// Asteroids datas
namespace Asteroids{
// List of all current asteroids
export let list: Sup.Actor[];
// Differents size of asteroids
export const sizes = {"big":1.5, "medium":1, "small":0.5};
// Different collision amplitude related to size
export const amplitudes = {"big":2.5, "medium":2, "small":1}
// Range for Z positions of asteroids
export enum zPositions {min = -28, max = 10};
// Starting asteroids number
export const startCount: number = 5;
// Current asteroids number
export let currentCount: number;
// Maximum asteroids number
export const maxCount: number = 10;
// Range of linear and rotation speed of asteroids
export enum linearSpeed {min = -0.05, max = 0.05};
export enum rotationSpeed {min = -0.01, max = 0.01};
// Starting time before asteroids spawning
export const respawnTime: number = 180;
// Current time before asteroids spawning
export let spawnTimer: number = 0;
}
Game.ts
class GameBehavior extends Sup.Behavior {
timer: number;
start() {
// When GameBehavior awake, if game is Asteroids then spawn asteroids and alien
if(Game.nameIndex === 0){
// Give to this game instance, the starting timer
this.timer = Game.timeMax;
// And update the HUD timer
Game.updateTimer(this.timer);
// Spawn an Alien ship
Game.spawnAlien();
// Spawn as much asteroids than we have set as a Starting number
for(let i = 0; i < Asteroids.startCount; i++){
// Spawn an asteroid
Game.spawnAsteroid();
}
}
}
update() {
// If the game is Asteroids then spawn alien and asteroids
if(Game.nameIndex === 0){
//If alien destroyed, spawn a new alien after a certain time
if(!Alien.alive){
// If spawnTimer not finished, decrease by one
if(Alien.spawnTimer > 0){
Alien.spawnTimer--;
// If spawnTimer finished, spawn an alien ship
}
else {
Game.spawnAlien();
}
}
// Spawn a new asteroid after a certain time until the overall number reach maximum
// If asteroid current count is less than the max number
if (Asteroids.currentCount < Asteroids.maxCount) {
// If spawnTimer is not finished, decrease by one
if (Asteroids.spawnTimer > 0) {
Asteroids.spawnTimer--;
}
// If spawnTimer is finished, create a big asteroid
else {
Game.spawnAsteroid();
// Reset timer for next asteroid
Asteroids.spawnTimer = Asteroids.respawnTime;
}
}
// Timer and game over screen decrease to each frame
if (this.timer > 0) {
this.timer--
// If 60 frames passed (which mean one second when converted), update
if(this.timer % 60 === 0) {
Game.updateTimer(this.timer);
}
// If timer at 0, then the game is finished.
}
else {
// The game is over, return ship1 score
Game.gameOver("ship1");
}
}
// Check if score need to be updated with the HUD
if (Game.checkScoreHUD) {
// If the game is spacewar, we update the two ship scores
if (Game.nameIndex == 1) {
let player1Score = Sup.getActor("Ship1").getBehavior(ShipBehavior).score;
let player2Score = Sup.getActor("Ship2").getBehavior(ShipBehavior).score;
Game.updateHUDScore(player1Score, player2Score);
}
// Else the game is asteroids, we update the ship 1 score
else {
let playerScore = Sup.getActor("Ship1").getBehavior(ShipBehavior).score;
Game.updateHUDScore(playerScore);
}
}
// Check if lifes need to be updated with the HUD
if (Game.checkLifeHUD) {
if (Game.nameIndex === 0) {
let playerLife = Sup.getActor("Ship1").getBehavior(ShipBehavior).lifes;
let alienLife = Alien.lifes;
Game.updateHUDLife(playerLife, alienLife);
}
if (Game.nameIndex === 1) {
let player1Life = Sup.getActor("Ship1").getBehavior(ShipBehavior).lifes;
let player2Life = Sup.getActor("Ship2").getBehavior(ShipBehavior).lifes;
Game.updateHUDLife(player1Life, player2Life);
}
}
// Restart game when key (R) is pressed, call Game.start function which reload the game scene
if (Sup.Input.wasKeyJustPressed("R")) {
Game.start();
}
// Leave Game when key (ESCAPE) is pressed, load the menu scene
if (Sup.Input.wasKeyJustPressed("ESCAPE")) {
Sup.loadScene("Menu/Scene");
}
}
}
Sup.registerBehavior(GameBehavior);
Alien.ts
class AlienBehavior extends Sup.Behavior {
// Ship size of this Actor
size: number;
// Ship amplitude of this Actor
amplitude: number;
// Ship position
position: Sup.Math.Vector2;
// Ship linear movement
velocity : Sup.Math.Vector2;
// Timer before shooting
shootCooldown: number;
// Timer before death
deathTimer: number;
awake() {
// Set Alien.alive flag to true
Alien.alive = true;
// Get a random index for alien ship size and amplitude
let randomShip: number = Sup.Math.Random.integer(0, 2);
// Get the default size related to the random index
this.size = Alien.sizes[randomShip];
// Get the default collision amplitude related to the random index
this.amplitude = Alien.amplitudes[randomShip];
// Set the size to the actor
this.actor.setLocalScale(this.size);
// Set the value of Alien.startLife to the current Alien.lifes
Alien.lifes = Alien.startLife;
// Set the shootCooldown timer to the Alien.shootTime value
this.shootCooldown = Alien.shootTime;
// Set the Game.checkLifeHUD value to true
Game.checkLifeHUD = true;
}
start() {
// Set position to the current actor position
this.position = this.actor.getLocalPosition().toVector2();
// Set x axis linear movement toward the opposite edge of spawn
if (this.position.x === Game.bounds.width / 2) {
this.velocity = new Sup.Math.Vector2(-Alien.linearSpeed, 0);
}
else {
this.velocity = new Sup.Math.Vector2(Alien.linearSpeed, 0);
}
}
shoot() {
// Create a new alien missile and set the Missile actor to a variable
let missile = Sup.appendScene("Alien/Missile/Prefab")[0];
// Set the alien ship position to the missile actor position
missile.setLocalPosition(this.position);
// Reset value of Timer to default value
this.shootCooldown = Alien.shootTime;
}
update() {
// Death timer
// Decrease death timer before destruction
if(this.deathTimer > 0){
this.deathTimer--;
if(this.deathTimer === 0){
this.actor.destroy();
}
return;
}
// Death setting
// Set death if alien don't have lifes anymore
if(Alien.lifes === 0){
Sup.Audio.playSound('Sounds/explosion');
// Reset angles to default for the explosion sprite
this.actor.setEulerAngles(0,0,0);
// Set visible off the alien ship model
this.actor.getChild("Model").setVisible(false);
// Set the sprite animation explode to play once without looping
this.actor.getChild('Destruction').spriteRenderer.setAnimation("explode", false);
// Give 30 frames before actor destruction (half a second)
this.deathTimer = 30;
// Add point to the player for alien death
Game.addPoints(true, Game.points.alien);
// Flag the game to check and update the HUD score
Game.checkScoreHUD = true;
}
// Keep moving
// Add the linear movement to the position variable
this.position.add(this.velocity);
// Set the new position to the alien actor
this.actor.setLocalPosition(this.position);
// Keep rotating
// Rotate actor using rotateLocalEulerY with the default Alien.rotationSpeed value
this.actor.rotateLocalEulerY(Alien.rotationSpeed);
// Keep shooting
// If the timer is not finished, decrease value of one
if (this.shootCooldown > 0) {
this.shootCooldown--;
}
// If the timer is finished, shoot missile
else {
Sup.Audio.playSound('Sounds/alienShot');
this.shoot();
}
// Stay on the screen
// If position is superior to the max of the x bound then switch position
if (this.position.x > Game.bounds.width / 2) {
this.position.x = -Game.bounds.width / 2;
}
// If position is inferior to the min of the x bound then switch position
if (this.position.x < -Game.bounds.width / 2) {
this.position.x = Game.bounds.width / 2;
}
// If there is player ship1 missiles, call a collision checking for this actor with the list of the player Ship missiles
if(Ships.missiles[0].length > 0){
// If the collision checking return true
if (Game.checkCollisionMissile(this.actor, Ships.missiles[0], this.amplitude)) {
Sup.Audio.playSound('Sounds/shotContact');
// Decrease Alien lifes by one
Alien.lifes--
// Flag true to check and update the life HUD in Game Script
Game.checkLifeHUD = true;
}
}
// Check collision between Alien ship and Player ship
if (Game.checkCollisionShip(this.actor, this.amplitude)){
// Destroy the alien ship by setting its lifes to 0
Alien.lifes = 0;
}
}
onDestroy() {
// Set Alien.alive flag to false
Alien.alive = false;
// Give to Alien.spawnTimer the value of Alien.respawnTime
Alien.spawnTimer = Alien.respawnTime;
}
}
Sup.registerBehavior(AlienBehavior);
Missile.ts (Alien)
class AlienMissileBehavior extends Sup.Behavior {
// Current position
position: Sup.Math.Vector2;
// Current velocity
velocity: Sup.Math.Vector2;
// Target position
target: Sup.Math.Vector2;
// Missile trajectory angle
angle: number;
start() {
// Set current position from the actor position
this.position = this.actor.getLocalPosition().toVector2();
// Get player ship position to define as target for this missile
this.target = Sup.getActor("Ship1").getLocalPosition().toVector2();
// Get angle trajectory between this actor position and the target position
this.angle = this.position.angleTo(this.target);
// Create velocity with the Alien.missileSpeed value
this.velocity = new Sup.Math.Vector2(Alien.missileSpeed, 0);
// Convert velocity with the angle trajectory
this.velocity.rotate(this.angle);
// Add the current actor the Alien.missiles list
Alien.missiles.push(this.actor);
}
update() {
// While the missile has no reached the target position, keep moving
// Add current velocity to current position
this.position.add(this.velocity);
// Update current position to missile actor
this.actor.setLocalPosition(this.position);
// Get the distance between current position and target position
let distance = this.target.distanceTo(this.position);
// When the distance to target is nearly reached, the missile explode
if (distance < 0.5) {
this.actor.getChild("Sprite").spriteRenderer.setAnimation("explode", false);
// When the distance is close to 0, the missile actor is destroyed
if (distance < 0.1) {
this.actor.destroy();
}
}
}
onDestroy() {
// Remove this actor from the Alien.missiles list
Alien.missiles.splice(Alien.missiles.indexOf(this.actor), 1);
}
}
Sup.registerBehavior(AlienMissileBehavior);
##### Asteroid.ts
class AsteroidBehavior extends Sup.Behavior {
// The size of the asteroid
size: number;
// The amplitude of this asteroid Actor
amplitude: number;
// The class of size this asteroid belong
sizeClass: string;
// The position of the asteroid
position: Sup.Math.Vector3;
// The movement of the asteroid
velocity: Sup.Math.Vector3;
// The movement of the asteroid on x axis
linearSpeedX: number;
// The movement of the asteroid on y axis
linearSpeedY: number;
// The rotation speed of the asteroid
rotationSpeed: number;
// Timer before destruction
deathTimer: number;
awake() {
// Increase asteroids count by one
Asteroids.currentCount++;
// Add this actor to the Asteroids list
Asteroids.list.push(this.actor);
}
start() {
// Get the position of the actor set randomly when spawned
this.position = this.actor.getLocalPosition();
// Get random value for linear speed on axis X and axis Y
this.linearSpeedX = Sup.Math.Random.float(Asteroids.linearSpeed.min, Asteroids.linearSpeed.max);
this.linearSpeedY = Sup.Math.Random.float(Asteroids.linearSpeed.min, Asteroids.linearSpeed.max);
// Set asteroid velocity with the linearSpeed values
this.velocity = new Sup.Math.Vector3(this.linearSpeedX, this.linearSpeedY, 0);
// Get random value for linear speed on axis X and axis Y
this.rotationSpeed = Sup.Math.Random.float(Asteroids.rotationSpeed.min, Asteroids.rotationSpeed.max);
// Set the asteroid size related to the classSize of the asteroid
this.size = Asteroids.sizes[this.sizeClass];
// Set the asteroid collision amplitude related to the classSize of the asteroid
this.amplitude = Asteroids.amplitudes[this.sizeClass];
// Set the size to the actor model
this.actor.getChild("Model").setLocalScale(this.size);
// Set the size to the destruction sprite
this.actor.getChild("Destruction").setLocalScale(this.size * 2);
}
die() {
Sup.Audio.playSound('Sounds/explosion');
// Reset angles to default for the explosion sprite
this.actor.setEulerAngles(0,0,0);
// Set visible off the asteroid model
this.actor.getChild("Model").setVisible(false);
// Set the sprite animation explode to play once without looping
this.actor.getChild('Destruction').spriteRenderer.setAnimation("explode", false);
// Give 30 frames before actor destruction (half a second)
this.deathTimer = 30;
// We give the points to ship1 related to the classSize of this asteroid
if(this.sizeClass === "big") {
Game.addPoints(true, Game.points.asteroidBig);
}
else if (this.sizeClass === "medium") {
Game.addPoints(true, Game.points.asteroidMedium);
}
else {
Game.addPoints(true, Game.points.asteroidSmall);
}
// Flag the game to check and update the HUD score
Game.checkScoreHUD = true;
}
spawnChildren() {
// Create two now asteroid and set the Actor asteroid to each variable
let asteroid1 = Sup.appendScene("Asteroid/Prefab")[0];
let asteroid2 = Sup.appendScene("Asteroid/Prefab")[0];
// Set the position of the new asteroids to the same position than the asteroid parent (this one)
asteroid1.setPosition(this.position);
asteroid2.setPosition(this.position);
// If the sizeClass was big, then both asteroid are medium
if (this.sizeClass === "big") {
asteroid1.getBehavior(AsteroidBehavior).sizeClass = "medium";
asteroid2.getBehavior(AsteroidBehavior).sizeClass = "medium";
}
// If the sizeClass was medium, then both asteroid are small
if (this.sizeClass === "medium") {
asteroid1.getBehavior(AsteroidBehavior).sizeClass = "small";
asteroid2.getBehavior(AsteroidBehavior).sizeClass = "small";
}
}
update() {
// Death timer
if(this.deathTimer > 0){
this.deathTimer--;
if(this.deathTimer === 0){
this.actor.destroy();
}
return;
}
// Keep moving
this.position.add(this.velocity);
this.actor.setLocalPosition(this.position);
// Keep rotating
this.actor.rotateEulerAngles(this.rotationSpeed, this.rotationSpeed, this.rotationSpeed);
// Stay on the screen
// Check position of asteroid on x axis
if (this.position.x > Game.bounds.width / 2) {
this.position.x = -Game.bounds.width / 2
}
if (this.position.x < -Game.bounds.width / 2) {
this.position.x = Game.bounds.width / 2
}
// Check position of asteroid on y axis
if (this.position.y > Game.bounds.height / 2) {
this.position.y = -Game.bounds.height / 2
}
if (this.position.y < -Game.bounds.height / 2) {
this.position.y = Game.bounds.height / 2
}
// If there is player ship1 missiles, call a collision checking for this actor with the list of the player Ship missiles
if(Ships.missiles[0].length > 0){
// If the collision checking return true
if (Game.checkCollisionMissile(this.actor, Ships.missiles[0], this.amplitude)) {
// Destroy this asteroid
this.die();
// If the asteroid is not small
if (this.sizeClass !== "small"){
// Spawn two new asteroid of the class below
this.spawnChildren();
}
}
}
}
onDestroy() {
// Decrease asteroids count by one
Asteroids.currentCount--;
// Remove this actor from the Asteroids list
Asteroids.list.splice(Asteroids.list.indexOf(this.actor), 1);
}
}
Sup.registerBehavior(AsteroidBehavior);
Ship.ts
class ShipBehavior extends Sup.Behavior {
// Ship index, 0 is ship 1, 1 is ship 2
index: number;
// Ship radius collision
amplitude: number;
// Ship current life
lifes: number;
// Ship current status
alive: boolean;
// Ship current score
score: number;
// Spawn position
spawnPosition: Sup.Math.Vector2;
// Current position
position: Sup.Math.Vector2;
// Current movement speed
linearVelocity = new Sup.Math.Vector2();
// Current rotation speed
angularVelocity: number;
// Angle position
angle: number;
// Timer before shooting
shootCooldown: number;
// Timer before respawn
spawnCooldown: number;
// Timer before vulnerability
invincibilityCooldown: number;
awake() {
// Starting life to 3
this.lifes = Ships.startLife;
// Set true to alive status
this.alive = true;
// Starting score to 0
this.score = Ships.startScore;
// Starting speed movement on x and y axis to 0
this.linearVelocity.set(0, 0);
// Starting speed rotation to 0
this.angularVelocity = 0;
}
start() {
// Set the ship default size to half size
this.actor.setLocalScale(Ships.size);
// Set the ship default amplitude related to size
this.amplitude = Ships.amplitude;
// Get the starting position to become the spawnPosition of this behavior
this.spawnPosition = this.actor.getLocalPosition().toVector2();
// Get the starting position to become the current position of this behavior
this.position = this.actor.getLocalPosition().toVector2();
// Get the starting angle to become the current angle of this behavior
this.angle = this.actor.getLocalEulerZ();
}
die() {
Sup.Audio.playSound('Sounds/explosion');
// Decrease life of one
this.lifes--;
// Set false to alive status
this.alive = false;
// Flag to check and update the life HUD
Game.checkLifeHUD = true;
// If life is 0, then the game is over
if (this.lifes === 0) {
// If this is the Asteroids game, death of ship mean victory for Alien
if(Game.nameIndex === 0) {
Sup.setTimeout(1000, function () { Game.gameOver("alien") });
}
else {
// If this is Spacewar game and death of ship 1 mean victory for ship 2
if (this.index === 0){
Sup.setTimeout(1000, function () { Game.gameOver("ship2") });
}
// Else, this is ship 2 and it is a victory for ship 1
else {
Sup.setTimeout(1000, function () { Game.gameOver("ship1") });
}
}
}
// Check which ship index to see which lose points
if (this.index === 0) {
Game.addPoints(true, Game.points.death);
}
else {
Game.addPoints(false, Game.points.death);
}
// Flag to check and update the score HUD
Game.checkScoreHUD = true;
// Set timer before respawn
this.spawnCooldown = Ships.respawnTimer;
// Set ship model visibility to false
this.actor.getChild('Model').setVisible(false);
// Set ship boosts visibility to false
this.actor.getChild('Boost').setVisible(false);
// Set sprite animation explosition to play once
this.actor.getChild('Destruction').spriteRenderer.setAnimation("explode", false);
// Reset speed movement on x and y axis to 0
this.linearVelocity.set(0, 0);
// Reset angular movement to 0
this.angularVelocity = 0;
// Reset angle to default for ship 1 or ship 2
if (this.index === 0){
this.angle = 1.6;
}
else{
this.angle = -1.6;
}
}
spawn() {
// The ship respawn to spawn position
this.position = this.spawnPosition.clone();
// Set the new current position to the Ship actor
this.actor.setLocalPosition(this.position);
// Set the new angle to the Ship actor
this.actor.setLocalEulerZ(this.angle);
// The ship model visibility to true
this.actor.getChild('Model').setVisible(true);
// Set timer for invincibility
this.invincibilityCooldown = Ships.invincibleTimer;
}
shoot() {
// Initialize a new missile
let missile: Sup.Actor;
// If the ship is ship 1 then create a Ship 1 missile and set the variable missile to the Missile actor
if (this.index === 0) {
missile = Sup.appendScene("Ship/0/Missile/Prefab")[0];
}
// Else do the same but for the missile of ship 2
else {
missile = Sup.appendScene("Ship/1/Missile/Prefab")[0];
}
// Set position of the actor to the current position of the ship
missile.setLocalPosition(this.position);
// Set local variables of the missile behavior
// Report the position of the ship to the variable position of the behavior
missile.getBehavior(ShipMissileBehavior).position = this.position.clone();
// Report the angle of the ship to the angle direction of the missile
missile.getBehavior(ShipMissileBehavior).angle = this.angle;
// Set the shipIndex related to this missile
missile.getBehavior(ShipMissileBehavior).shipIndex = this.index;
// Set Shooting timer to be able to shoot again
this.shootCooldown = Ships.shootingTimer;
}
boost(intensity: string) {
// Create a new variable boost that get the Boost actor child of Ship actor
let boost:Sup.Actor = this.actor.getChild("Boost");
// Set the boost actor visible true
boost.setVisible(true);
// Set animation to both sprite with the intensity normal or fast
boost.getChild("0").spriteRenderer.setAnimation(intensity);
boost.getChild("1").spriteRenderer.setAnimation(intensity);
}
rotateBoost(direction: string) {
// Create a new variable boost that get the Boost actor child of Ship actor
let boost:Sup.Actor = this.actor.getChild("Boost");
// Set the boost actor visible true
boost.setVisible(true);
// If rotate on the left direction
if(direction === "left"){
// Switch animation for right boost stronger
boost.getChild("0").spriteRenderer.setAnimation("fast");
boost.getChild("1").spriteRenderer.setAnimation("normal");
}
// If rotate on the right direction
if(direction === "right"){
// Switch animation for left boost stronger
boost.getChild("1").spriteRenderer.setAnimation("fast");
boost.getChild("0").spriteRenderer.setAnimation("normal");
}
}
update() {
// Keep respawning
// If the spawnCooldown timer is more than 0
if (this.spawnCooldown > 0) {
// Decrease by one the timer
this.spawnCooldown--
// If the spawnCooldown is 0
if (this.spawnCooldown === 0) {
// Call the spawn method
this.spawn();
}
//restart update loop to skip the following code
return;
}
// Keep shooting
// If the shootCooldown timer is more than 0
if (this.shootCooldown > 0) {
// Decrease by one the timer
this.shootCooldown--;
}
// If the timer is 0 (!0 = true)
if (!this.shootCooldown) {
// If the shoot key is pressed
if(Sup.Input.wasKeyJustPressed(Ships.commands[this.index].shoot)){
Sup.Audio.playSound('Sounds/shipShot');
// Call the shoot method
this.shoot();
}
}
// Keep moving
// If forward key is pressed down
if (Sup.Input.isKeyDown(Ships.commands[this.index].forward)){
// Set the impulse with the linearAcceleration
let impulse = new Sup.Math.Vector2(Ships.linearAcceleration, 0);
// Convert the impulse to the current angle
impulse.rotate(this.angle);
// Add the impulse to the linearVelocity
this.linearVelocity.add(impulse);
// Call the boost method with a normal intensity
this.boost("normal");
// If the boost key is pressed down
if (Sup.Input.isKeyDown(Ships.commands[this.index].boost)) {
// Add a second time the impulse to the linearVelocity
this.linearVelocity.add(impulse);
// Call the boost method with a fast intensity
this.boost("fast");
}
}
else {
// Set visible false booster if not going forward
this.actor.getChild("Boost").setVisible(false);
}
// Keep rotating
// If left key is pressed down
if (Sup.Input.isKeyDown(Ships.commands[this.index].left)){
// The angularVelocity get the angularAcceleration
this.angularVelocity += Ships.angularAcceleration;
// Boost sprite for left side
this.rotateBoost("left");
}
// If right key is pressed down
if (Sup.Input.isKeyDown(Ships.commands[this.index].right)){
// The angularVelocity get the opposite angularAcceleration
this.angularVelocity -= Ships.angularAcceleration;
// Boost sprite for left side
this.rotateBoost("right");
}
// Set boost to default if key left, right and forward are NOT pressed
if (!Sup.Input.isKeyDown(Ships.commands[this.index].left) &&
!Sup.Input.isKeyDown(Ships.commands[this.index].right) &&
!Sup.Input.isKeyDown(Ships.commands[this.index].forward)){
this.actor.getChild("Boost").setVisible(false);
this.actor.getChild("Boost").getChild("0").setVisible(true);
this.actor.getChild("Boost").getChild("1").setVisible(true);
}
// Keep slowing down
// The linearVelocity multiply the linearDamping
this.linearVelocity.multiplyScalar(Ships.linearDamping);
// The angularVelocity multiply the angularDamping
this.angularVelocity *= Ships.angularDamping;
// Stay on the game screen
if (this.position.x > Game.bounds.width / 2) {
this.position.x = -Game.bounds.width / 2;
}
if (this.position.x < -Game.bounds.width / 2) {
this.position.x = Game.bounds.width / 2;
}
if (this.position.y > Game.bounds.height / 2) {
this.position.y = -Game.bounds.height / 2;
}
if (this.position.y < -Game.bounds.height / 2) {
this.position.y = Game.bounds.height / 2;
}
// Update position and angle
// Add the linearVelocity to the current position
this.position.add(this.linearVelocity);
// Set the new current position to the Ship actor
this.actor.setLocalPosition(this.position);
// Add the angularVelocity to the current angle
this.angle += this.angularVelocity;
// Set the new angle to the Ship actor
this.actor.setLocalEulerZ(this.angle);
// Blinking
// If the invincibilityCooldown Timer is more than 0
if (this.invincibilityCooldown > 0) {
// Decrease by one the timer
this.invincibilityCooldown--;
// Set actor visible become true every half second, false the other half and stay visible at the end
this.actor.setVisible(this.invincibilityCooldown % 60 < 30);
// When invincibilityCooldown reach 1, get back vulnerability
if (this.invincibilityCooldown === 1) {
// Set true to alive status
this.alive = true;
}
// Restart update loop to skip the collision blocks code
return;
}
// If game is Super Asteroids, chek for collision with asteroids, alien missiles and alien ship
if (Game.nameIndex === 0) {
// Check collision between the player ship and the alien missiles
if (Game.checkCollisionMissile(this.actor, Alien.missiles, this.amplitude)){
this.die();
}
// Check collision between the player ship and the asteroids
if (Game.checkCollisionAsteroids(this.actor, this.amplitude)){
this.die();
}
}
// If game is Super Spacewar, check collision with other missiles and other ship
if (Game.nameIndex === 1) {
// If the ship is 1 check collision with ship 2 missile
if (this.index === 0){
if (Game.checkCollisionMissile(this.actor, Ships.missiles[1], this.amplitude)){
// if there is collision, add point to the ship 2 and destroy ship 1
Game.addPoints(false, Game.points.ship);
this.die();
}
}
// Else the ship is 2 check collision with ship 1 missile
else {
if (Game.checkCollisionMissile(this.actor, Ships.missiles[0], this.amplitude)){
// if there is collision, add point to the ship 1 and destroy ship 2
Game.addPoints(true, Game.points.ship);
this.die();
}
}
// Check collision between this ship and the other ship
if (Game.checkCollisionShip(this.actor, this.amplitude)) {
this.die();
}
}
}
}
Sup.registerBehavior(ShipBehavior);
Missile.ts (Ship)
class ShipMissileBehavior extends Sup.Behavior {
// shipIndex owner of this missile actor
shipIndex: number;
// Current position
position: Sup.Math.Vector2;
// Current movement velocity
velocity: Sup.Math.Vector2;
// Missile trajectory angle
angle: number;
// Timer before death
lifeTime: number;
start() {
// Set the timer lifeTime to the default value Ships.missileLife
this.lifeTime = Ships.missileLife;
// Create a new vector with the default Ships.missileSpeed as value for the velocity
this.velocity = new Sup.Math.Vector2(Ships.missileSpeed, 0);
// Convert the velocity with the trajectory angle
this.velocity.rotate(this.angle);
// Add the current missile actor to the global Ships.missiles[shipIndex] list (0 for ship1 and 1 for ship2)
Ships.missiles[this.shipIndex].push(this.actor);
}
update() {
// Keep moving
this.position.add(this.velocity);
this.actor.setLocalPosition(this.position);
// If the timer is superior to 0, decrease by one
if (this.lifeTime > 0) {
this.lifeTime--;
// If the timer reach 10 frame before death, play the destruction animation once
if (this.lifeTime === 10) {
this.actor.getChild("Sprite").spriteRenderer.setAnimation("explode", false);
}
}
// Once the lifeTime timer reach 0, destroy the Actor
else {
this.actor.destroy();
}
}
onDestroy() {
// Remove the current actor from the Global list from the shipIndex owner
Ships.missiles[this.shipIndex].splice(Ships.missiles[this.shipIndex].indexOf(this.actor), 1);
}
}
Sup.registerBehavior(ShipMissileBehavior);
Menu.ts
class MenuBehavior extends Sup.Behavior {
// The current menu screen
screen: string;
// Ray casting
ray = new Sup.Math.Ray();
// First button
button0: Sup.Actor;
// Second button
button1: Sup.Actor;
awake() {
// Set the menu with the Main screen
this.setScreen(Menu.screens.main);
// Update the buttons
this.updateButtonsText();
}
setScreen(screenName: string){
// Set the current screen to the screen string Name
this.screen = screenName;
// Loop through all the screen of the scene and set visible the current screen
for(let screen in Menu.screens){
// If the screen of the loop is the same as the current screen
if (Menu.screens[screen] == this.screen){
// Set visible true the screen
Sup.getActor("Screens").getChild(Menu.screens[screen]).setVisible(true);
}
// Else, hide the screen, set visible false
else {
Sup.getActor("Screens").getChild(Menu.screens[screen]).setVisible(false);
}
}
// call the function updateTitle
this.updateTitle();
}
updateTitle(){
// Set title visible true
Sup.getActor("Title").setVisible(true);
// Set score visible false
Sup.getActor("Score").setVisible(false);
// Change the title depending if the game is asteroids or spacewar
if(this.screen === Menu.screens.asteroids|| this.screen === Menu.screens.spacewar){
Sup.getActor("Title").getChild("Text2").textRenderer.setText(this.screen);
}
// Else, it change the title with an empty string
else{
Sup.getActor("Title").getChild("Text2").textRenderer.setText("");
}
}
updateButtonsText() {
// Get the two buttons actors in one variable each
this.button0 = Sup.getActor("Buttons").getChild("Button1");
this.button1 = Sup.getActor("Buttons").getChild("Button2");
// If it is the Main screen
if(this.screen === Menu.screens.main){
// Set the button to display the game name
this.button0.getChild("Text").textRenderer.setText("asteroids");
this.button1.getChild("Text").textRenderer.setText("spacewar");
}
// For the other screens
else {
// Set the button to display start and return
this.button0.getChild("Text").textRenderer.setText("start");
this.button1.getChild("Text").textRenderer.setText("return");
}
}
update() {
// Update the position of the raycaster of the mouse
this.ray.setFromCamera(Sup.getActor("Camera").camera, Sup.Input.getMousePosition());
// Return an object if the raycaster intersect the actor buttons
let hitB1 = this.ray.intersectActor(this.button0.getChild("Sprite"));
let hitB2 = this.ray.intersectActor(this.button1.getChild("Sprite"));
// If the button 1 is hovered
if(hitB1[0]){
// Change the opacity of the button to full bright
this.button0.getChild("Sprite").spriteRenderer.setOpacity(1);
// If the left mouse button is pressed
if (Sup.Input.wasMouseButtonJustPressed(0)) {
Sup.Audio.playSound("Sounds/shipShot");
// Differents case possible depending the current screen
switch (this.screen){
// If the current screen is the Main screen
case Menu.screens.main:
// Set the new screen to Asteroids screen
this.setScreen(Menu.screens.asteroids);
break;
// If the current screen is the Asteroid screen
case Menu.screens.asteroids:
// Set the nameIndex to 0
Game.nameIndex = Menu.names.Asteroids;
// Start the game
Game.start();
return;
// If the current screen is the Spacewar screen
case Menu.screens.spacewar:
// Set the nameIndex to 1
Game.nameIndex = Menu.names.Spacewar;
// Start the game
Game.start();
return;
// If the current screen is the Game Over screen
case Menu.screens.gameover:
// Restart the game
Game.start();
return;
}
}
}
// If the button is not hovered, set opacity half bright
else{
this.button0.getChild("Sprite").spriteRenderer.setOpacity(0.5);
}
// If the button 2 is hovered
if(hitB2[0]){
// Change the opacity of the button to full bright
this.button1.getChild("Sprite").spriteRenderer.setOpacity(1);
// If the left mouse button is pressed
if (Sup.Input.wasMouseButtonJustPressed(0)) {
Sup.Audio.playSound("Sounds/shipShot");
// Loop through different case
switch (this.screen){
// If the current screen is the Main screen
case Menu.screens.main:
// Set the screen of the Spacewar game screen
this.setScreen(Menu.screens.spacewar);
break;
// Else, in other case, return to main screen
default:
this.setScreen(Menu.screens.main);
}
}
}
// If the button is not hovered, set opacity half bright
else{
this.button1.getChild("Sprite").spriteRenderer.setOpacity(0.5);
}
// Update the buttons
this.updateButtonsText();
}
}
Sup.registerBehavior(MenuBehavior);
Background.ts
class BackgroundBehavior extends Sup.Behavior {
// Initialize position and speed variables
position: number;
speed : number;
awake() {
// Get the position on Y axis of the actor
this.position = this.actor.getLocalY();
// Set the speed of background scrolling
this.speed = 0.01;
}
update() {
// Add the speed movement to the current position
this.position += this.speed;
// Set the current position to the actor
this.actor.setLocalY(this.position);
// If the sprite moved all its height (480/16 = 60 units)
if (this.position > 60) {
// Then return down to start again
this.position = -60;
}
}
}
Sup.registerBehavior(BackgroundBehavior);