Move the game to subfolder
This commit is contained in:
parent
a724d80bb7
commit
a86c5cdda0
39 changed files with 0 additions and 0 deletions
97
game/src/classes/Asteroid.ts
Normal file
97
game/src/classes/Asteroid.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
import Phaser from 'phaser'
|
||||
import Bullet from '../classes/Bullet'
|
||||
|
||||
export default class Asteroid extends Phaser.Physics.Arcade.Sprite {
|
||||
// asteroid can't kill player
|
||||
// if younger than unbornAge in ms
|
||||
static unbornAge = 1000
|
||||
|
||||
readonly wrapMargin = 30
|
||||
readonly scaleMin = 0.7
|
||||
readonly scaleMax = 1.3
|
||||
readonly scaleRotationFactor = 0.4
|
||||
|
||||
age = 0
|
||||
|
||||
constructor(scene: Phaser.Scene) {
|
||||
super(
|
||||
scene,
|
||||
Phaser.Math.RND.integerInRange(0, scene.physics.world.bounds.width),
|
||||
Phaser.Math.RND.integerInRange(0, scene.physics.world.bounds.height),
|
||||
'asteroids'
|
||||
)
|
||||
|
||||
scene.add.existing(this)
|
||||
scene.physics.add.existing(this)
|
||||
|
||||
this.setCircle(30, 30, 30)
|
||||
this.setScale(Phaser.Math.RND.realInRange(this.scaleMin, this.scaleMax))
|
||||
this.setVelocity(
|
||||
Phaser.Math.RND.realInRange(-100, 100),
|
||||
Phaser.Math.RND.realInRange(-100, 100)
|
||||
)
|
||||
this.setRandomShade()
|
||||
|
||||
this.anims.play(Asteroid.getRandomAnimationName())
|
||||
this.anims.timeScale = 1 + (this.scaleMax - this.scale) * this.scaleRotationFactor
|
||||
if (Phaser.Math.RND.integer() % 2 == 0)
|
||||
this.anims.reverse()
|
||||
|
||||
this.setAlpha(0)
|
||||
scene.tweens.addCounter({
|
||||
from: 0,
|
||||
to: 1,
|
||||
duration: Asteroid.unbornAge,
|
||||
onUpdate: (tween) => {
|
||||
const value = tween.getValue()
|
||||
this.setAlpha(value)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
preUpdate(time: number, delta: number) {
|
||||
super.preUpdate(time, delta)
|
||||
|
||||
this.scene.physics.world.wrap(this, this.scale * this.wrapMargin)
|
||||
this.age += delta
|
||||
}
|
||||
|
||||
gotHit(me, bullet) {
|
||||
if (!(bullet instanceof Bullet)) return
|
||||
if (bullet.active == false) return
|
||||
|
||||
me.scene.events.emit("asteroid:destroy")
|
||||
me.destroy() // TODO: use objects pool
|
||||
bullet.setActive(false)
|
||||
bullet.setVisible(false)
|
||||
}
|
||||
|
||||
private setRandomShade() {
|
||||
const color = new Phaser.Display.Color()
|
||||
color.randomGray(0xa0) //the darkest possible dye is 0xa0a0a0
|
||||
this.setTint(color.color)
|
||||
}
|
||||
|
||||
static createAnimations(scene: Phaser.Scene) {
|
||||
["a", "b", "c", "d"].forEach((animationName, i) => {
|
||||
const frames = scene.anims.generateFrameNames('asteroids', {
|
||||
start: 0, end: 15,
|
||||
zeroPad: 4,
|
||||
prefix: `${animationName}4`
|
||||
});
|
||||
|
||||
scene.anims.create({
|
||||
key: `asteroid${i}`,
|
||||
frames: frames,
|
||||
frameRate: 16,
|
||||
repeat: -1
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
static getRandomAnimationName() {
|
||||
const animationsAmount = 3
|
||||
const id = Phaser.Math.RND.integerInRange(0, animationsAmount)
|
||||
return `asteroid${id}`
|
||||
}
|
||||
}
|
||||
36
game/src/classes/Bullet.ts
Normal file
36
game/src/classes/Bullet.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import Phaser from 'phaser'
|
||||
|
||||
export default class Bullet extends Phaser.Physics.Arcade.Sprite {
|
||||
readonly lifetime = 4000 //ms
|
||||
readonly speed = 600
|
||||
|
||||
age = 0
|
||||
|
||||
constructor(scene, x, y) {
|
||||
super(scene, x, y, 'bullet')
|
||||
}
|
||||
|
||||
fire(x: number, y: number, rotation: number) {
|
||||
this.body.reset(x, y)
|
||||
this.rotation = rotation
|
||||
|
||||
this.setActive(true)
|
||||
this.setVisible(true)
|
||||
|
||||
const v = new Phaser.Math.Vector2(0, -this.speed)
|
||||
v.rotate(rotation)
|
||||
this.setVelocity(v.x, v.y)
|
||||
this.age = 0
|
||||
}
|
||||
|
||||
preUpdate(time: number, delta: number) {
|
||||
super.preUpdate(time, delta)
|
||||
|
||||
this.age += delta
|
||||
|
||||
if (this.age >= this.lifetime) {
|
||||
this.setActive(false)
|
||||
this.setVisible(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
32
game/src/classes/Bullets.ts
Normal file
32
game/src/classes/Bullets.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import Phaser from 'phaser'
|
||||
import Bullet from './Bullet'
|
||||
import Ship from './Ship'
|
||||
|
||||
export default class Bullets extends Phaser.Physics.Arcade.Group {
|
||||
readonly cooldown: number //ms
|
||||
|
||||
lastShoot = 0
|
||||
|
||||
constructor(scene: Phaser.Scene, fireRate: number) {
|
||||
super(scene.physics.world, scene)
|
||||
|
||||
this.createMultiple({
|
||||
frameQuantity: 30,
|
||||
key: 'bullet',
|
||||
active: false,
|
||||
visible: false,
|
||||
classType: Bullet
|
||||
});
|
||||
|
||||
this.cooldown = 1000 / fireRate
|
||||
}
|
||||
|
||||
fireBullet(time: number, shooter: Ship) {
|
||||
let bullet = this.getFirstDead(false)
|
||||
|
||||
if (bullet && this.lastShoot + this.cooldown <= time) {
|
||||
bullet.fire(shooter.x, shooter.y, shooter.rotation)
|
||||
this.lastShoot = time
|
||||
}
|
||||
}
|
||||
}
|
||||
59
game/src/classes/DifficultyManager.ts
Normal file
59
game/src/classes/DifficultyManager.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import PlayScene from '../scenes/PlayScene'
|
||||
|
||||
export default class DifficultyManager {
|
||||
readonly spawnInterval = 1500 //ms
|
||||
readonly maxAsteroids = 300
|
||||
readonly level = 30
|
||||
readonly nextLevelRequirementIncrease = 10
|
||||
|
||||
private scene: PlayScene
|
||||
private difficultyLevel = 1
|
||||
private points = 0
|
||||
|
||||
private spawnAtOnce = 1
|
||||
private nextLevelRequirement = 10
|
||||
|
||||
constructor(scene: PlayScene) {
|
||||
this.scene = scene
|
||||
|
||||
scene.events.on('asteroid:destroy', () => {
|
||||
this.points += 1
|
||||
this.nextLevelRequirement -= 1
|
||||
this.scene.events.emit("getpoint", this.difficultyLevel)
|
||||
|
||||
if (this.nextLevelRequirement <= 0)
|
||||
this.levelUp()
|
||||
})
|
||||
|
||||
scene.time.addEvent({
|
||||
delay: this.spawnInterval,
|
||||
callback: this.spawnAsteroids,
|
||||
callbackScope: this,
|
||||
repeat: -1
|
||||
});
|
||||
}
|
||||
|
||||
levelUp() {
|
||||
this.difficultyLevel += 1
|
||||
this.spawnAtOnce += 1
|
||||
this.nextLevelRequirement = this.difficultyLevel * this.nextLevelRequirementIncrease
|
||||
this.scene.events.emit("lvlup", this.difficultyLevel)
|
||||
}
|
||||
|
||||
spawnAsteroids() {
|
||||
for (let i = 0; i < this.spawnAtOnce; ++i)
|
||||
this.scene.spawnAsteroid()
|
||||
}
|
||||
|
||||
getMaxAsteroids() {
|
||||
return Math.min(this.difficultyLevel * 5, this.maxAsteroids)
|
||||
}
|
||||
|
||||
getLevel() {
|
||||
return this.difficultyLevel
|
||||
}
|
||||
|
||||
getPoints() {
|
||||
return this.points
|
||||
}
|
||||
}
|
||||
86
game/src/classes/Ship.ts
Normal file
86
game/src/classes/Ship.ts
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
import Phaser from 'phaser'
|
||||
import Bullets from './Bullets'
|
||||
import Thruster from './Thruster'
|
||||
import Asteroid from './Asteroid'
|
||||
|
||||
export default class Ship extends Phaser.Physics.Arcade.Sprite {
|
||||
readonly acceleration = 5
|
||||
readonly dragForce = 0.6
|
||||
readonly maxSpeed = 300
|
||||
|
||||
readonly colliderRadiusRatio = 0.43
|
||||
readonly wrapMargin = 10
|
||||
|
||||
readonly fireRate = 5 //shoots/s
|
||||
|
||||
bullets: Bullets
|
||||
thruster: Thruster
|
||||
life = 3
|
||||
|
||||
constructor(scene: Phaser.Scene) {
|
||||
super(
|
||||
scene,
|
||||
scene.physics.world.bounds.centerX,
|
||||
scene.physics.world.bounds.centerY,
|
||||
'ship'
|
||||
)
|
||||
|
||||
scene.add.existing(this)
|
||||
scene.physics.add.existing(this)
|
||||
|
||||
scene.input.on('pointermove', (pointer) => {
|
||||
this.rotation = Phaser.Math.Angle.BetweenPoints(this, pointer) + Math.PI / 2
|
||||
})
|
||||
|
||||
this.setDamping(true)
|
||||
this.setDrag(this.dragForce)
|
||||
this.body.setCircle(this.width * this.colliderRadiusRatio)
|
||||
|
||||
this.bullets = new Bullets(scene, this.fireRate)
|
||||
this.thruster = new Thruster(scene, this)
|
||||
this.setMaxVelocity(this.maxSpeed)
|
||||
}
|
||||
|
||||
preUpdate(time: number, delta: number) {
|
||||
super.preUpdate(time, delta)
|
||||
|
||||
const keyUp = this.scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W)
|
||||
const keyDown = this.scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S)
|
||||
const keyLeft = this.scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A)
|
||||
const keyRight = this.scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D)
|
||||
|
||||
const vec = new Phaser.Math.Vector2(0, 0)
|
||||
|
||||
if (keyUp.isDown) vec.y = -this.acceleration
|
||||
if (keyDown.isDown) vec.y = this.acceleration
|
||||
if (keyRight.isDown) vec.x = this.acceleration
|
||||
if (keyLeft.isDown) vec.x = -this.acceleration
|
||||
|
||||
if (this.scene.input.activePointer.leftButtonDown())
|
||||
this.bullets!.fireBullet(time, this);
|
||||
|
||||
this.rotation = Phaser.Math.Angle.BetweenPoints(
|
||||
this,
|
||||
this.scene.input.activePointer
|
||||
) + Math.PI / 2
|
||||
|
||||
this.body.velocity.add(vec)
|
||||
this.scene.physics.world.wrap(this, this.wrapMargin)
|
||||
this.thruster.update(time, delta)
|
||||
}
|
||||
|
||||
gotHit(_, asteroid) {
|
||||
if (!(asteroid instanceof Asteroid)) return
|
||||
|
||||
if (asteroid.age > Asteroid.unbornAge) {
|
||||
this.life -= 1
|
||||
this.scene.cameras.main.shake(100, 0.02)
|
||||
asteroid.destroy() //TODO: use objects pool
|
||||
this.scene.events.emit("ship:gothit")
|
||||
}
|
||||
|
||||
if (!this.life){
|
||||
this.scene.events.emit("ship:destroyed")
|
||||
}
|
||||
}
|
||||
}
|
||||
59
game/src/classes/Thruster.ts
Normal file
59
game/src/classes/Thruster.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import Phaser from 'phaser'
|
||||
import Utils from './Utils'
|
||||
|
||||
export default class Thruster {
|
||||
readonly angleSpan = 40
|
||||
readonly frequency = 100
|
||||
readonly speed = 100
|
||||
readonly framesIndex = 30
|
||||
|
||||
emitter: Phaser.GameObjects.Particles.ParticleEmitter
|
||||
parent: Phaser.Physics.Arcade.Sprite
|
||||
|
||||
constructor(scene: Phaser.Scene, parent: Phaser.Physics.Arcade.Sprite) {
|
||||
this.emitter = scene.add.particles('particles')
|
||||
.createEmitter({
|
||||
frame: [25, 26, 27, 28, 29, 30, 31, 32, 34, 35],
|
||||
speed: this.speed,
|
||||
frequency: this.frequency,
|
||||
scale: { start: 0.2, end: 0 },
|
||||
blendMode: 'ADD',
|
||||
follow: parent
|
||||
})
|
||||
|
||||
this.parent = parent
|
||||
}
|
||||
|
||||
update(time: number, delta: number) {
|
||||
const thrustDirection = Phaser.Math.RadToDeg(
|
||||
this.parent.body.velocity.clone().negate().angle()
|
||||
)
|
||||
|
||||
this.emitter.angle.start = thrustDirection - this.angleSpan / 2
|
||||
this.emitter.angle.end = thrustDirection + this.angleSpan / 2
|
||||
|
||||
const thrustPower = this.getThrustPower()
|
||||
|
||||
this.emitter.setFrequency(thrustPower.frequency)
|
||||
this.emitter.setAlpha(thrustPower.opacity)
|
||||
}
|
||||
|
||||
getThrustPower() {
|
||||
const velocityRange = [0, 320] as const
|
||||
const frequencyRange = [300, 0] as const
|
||||
const opacityRange = [0, 1] as const
|
||||
|
||||
return {
|
||||
frequency: Utils.clampMap(
|
||||
this.parent.body.velocity.length(),
|
||||
...velocityRange,
|
||||
...frequencyRange
|
||||
),
|
||||
opacity: Utils.clampMap(
|
||||
this.parent.body.velocity.length(),
|
||||
...velocityRange,
|
||||
...opacityRange
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
49
game/src/classes/Utils.ts
Normal file
49
game/src/classes/Utils.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
export default {
|
||||
map(value: number,
|
||||
sourceMin: number,
|
||||
sourceMax: number,
|
||||
targetMin: number,
|
||||
targetMax: number) {
|
||||
|
||||
const sourceRange = sourceMax - sourceMin
|
||||
const targetRange = targetMax - targetMin
|
||||
return (value - sourceMin) / sourceRange * targetRange + targetMin
|
||||
},
|
||||
|
||||
clamp(value: number,
|
||||
min: number,
|
||||
max: number) {
|
||||
let leftLimit = Math.min
|
||||
let rightLimit = Math.max
|
||||
|
||||
if (max < min) {
|
||||
leftLimit = Math.max
|
||||
rightLimit = Math.max
|
||||
}
|
||||
|
||||
return leftLimit(
|
||||
rightLimit(min, value),
|
||||
max)
|
||||
},
|
||||
|
||||
clampMap(value: number,
|
||||
sourceMin: number,
|
||||
sourceMax: number,
|
||||
targetMin: number,
|
||||
targetMax: number) {
|
||||
|
||||
const v = this.map(value,
|
||||
sourceMin,
|
||||
sourceMax,
|
||||
targetMin,
|
||||
targetMax
|
||||
)
|
||||
|
||||
const min = Math.min(targetMin, targetMax)
|
||||
const max = Math.max(targetMin, targetMax)
|
||||
|
||||
return this.clamp(
|
||||
v, min, max
|
||||
)
|
||||
}
|
||||
}
|
||||
124
game/src/gui.ts
Normal file
124
game/src/gui.ts
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
declare interface Window { myStuff: any }
|
||||
|
||||
(() => {
|
||||
const elements = {
|
||||
bar: {
|
||||
logged: document.getElementById("loggedbar"),
|
||||
loggedout: document.getElementById("loggedoutbar"),
|
||||
},
|
||||
buttons: {
|
||||
login: document.getElementById("login"),
|
||||
logout: document.getElementById("logout"),
|
||||
signup: document.getElementById("signup"),
|
||||
},
|
||||
name: document.getElementById("name"),
|
||||
key: document.getElementById("key"),
|
||||
}
|
||||
|
||||
function checkIfLogged() {
|
||||
const token = localStorage.getItem("token")
|
||||
const name = localStorage.getItem("name")
|
||||
if (token !== null) {
|
||||
window.myStuff.token = token
|
||||
window.myStuff.name = name
|
||||
console.log("my stuff", window.myStuff)
|
||||
|
||||
elements.bar.logged!.style.display = ""
|
||||
elements.bar.loggedout!.style.display = "none"
|
||||
elements.name!.innerText = name!;
|
||||
elements.key!.innerText = token!;
|
||||
} else {
|
||||
console.log("not logged in")
|
||||
elements.bar.logged!.style.display = "none"
|
||||
elements.bar.loggedout!.style.display = ""
|
||||
}
|
||||
}
|
||||
|
||||
function loginByKey() {
|
||||
const key = prompt("Type in the #key")
|
||||
|
||||
if (!key) {
|
||||
alert("Login cancelled")
|
||||
return
|
||||
}
|
||||
|
||||
//TODO: fetch data from server
|
||||
const response = {
|
||||
token: Math.random().toString() + '.abc',
|
||||
name: 'Hagis'
|
||||
}
|
||||
|
||||
localStorage.setItem('token', response.token)
|
||||
localStorage.setItem('name', response.name)
|
||||
|
||||
window.myStuff.token = response.token
|
||||
window.myStuff.name = response.name
|
||||
|
||||
elements.bar.logged!.style.display = ''
|
||||
elements.bar.loggedout!.style.display = 'none'
|
||||
elements.name!.innerText = response.name
|
||||
elements.key!.innerText = response.token
|
||||
}
|
||||
|
||||
function signup() {
|
||||
const nickname = prompt("Your nickname:")
|
||||
|
||||
if (!nickname) {
|
||||
alert("Signup cancelled")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Fetch data from server
|
||||
|
||||
//mock bad request
|
||||
if (nickname == 'Hgs') {
|
||||
alert("The name is occupied by someone else, try again with another nickname")
|
||||
return
|
||||
}
|
||||
|
||||
const response = {
|
||||
token: Math.random().toString() + '.abc',
|
||||
name: nickname!
|
||||
}
|
||||
|
||||
localStorage.setItem('token', response.token)
|
||||
localStorage.setItem('name', response.name)
|
||||
|
||||
window.myStuff.token = response.token
|
||||
window.myStuff.name = response.name
|
||||
|
||||
elements.bar.logged!.style.display = ''
|
||||
elements.bar.loggedout!.style.display = 'none'
|
||||
elements.name!.innerText = response.name
|
||||
elements.key!.innerText = response.token
|
||||
}
|
||||
|
||||
function logout() {
|
||||
const sure = confirm("Are you sure you want to logout? " +
|
||||
"You won't be able to login again without #key. " +
|
||||
"Make sure you copied key before log out!")
|
||||
|
||||
if (!sure)
|
||||
return
|
||||
|
||||
localStorage.clear()
|
||||
window.myStuff = {}
|
||||
|
||||
elements.bar.logged!.style.display = 'none'
|
||||
elements.bar.loggedout!.style.display = ''
|
||||
elements.name!.innerText = ''
|
||||
elements.key!.innerText = ''
|
||||
}
|
||||
|
||||
function setup() {
|
||||
window.myStuff = {}
|
||||
|
||||
elements.buttons.login!.addEventListener("click", loginByKey)
|
||||
elements.buttons.logout!.addEventListener("click", logout)
|
||||
elements.buttons.signup!.addEventListener("click", signup)
|
||||
|
||||
checkIfLogged()
|
||||
}
|
||||
|
||||
setup()
|
||||
})()
|
||||
25
game/src/index.html
Normal file
25
game/src/index.html
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<title>SPACE SMASHER 9001!</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="bar">
|
||||
<div id="loggedbar" class="logged-in" style="display: none">
|
||||
Logged in as <span id="name">username</span>
|
||||
<span id="key" class="key">#asdasdasdasd</span>
|
||||
<button id="logout">Log out</button>
|
||||
</div>
|
||||
<div id="loggedoutbar" class="logged-out" style="display: none">
|
||||
Not logged in
|
||||
<button id="login">Log in with #key</button>
|
||||
<button id="signup">Sign up</button>
|
||||
</div>
|
||||
</div>
|
||||
<script src="main.ts"></script>
|
||||
<script src="gui.ts"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
22
game/src/main.ts
Normal file
22
game/src/main.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import Phaser, { Game } from 'phaser'
|
||||
|
||||
import PlayScene from './scenes/PlayScene'
|
||||
import GameOverScene from './scenes/GameOverScene'
|
||||
import StartScene from './scenes/StartScene'
|
||||
|
||||
const config: Phaser.Types.Core.GameConfig = {
|
||||
type: Phaser.AUTO,
|
||||
|
||||
width: 800,
|
||||
height: 600,
|
||||
|
||||
physics: {
|
||||
default: 'arcade',
|
||||
arcade: {
|
||||
debug: false
|
||||
}
|
||||
},
|
||||
scene: [StartScene, PlayScene, GameOverScene]
|
||||
}
|
||||
|
||||
export default new Phaser.Game(config)
|
||||
43
game/src/scenes/GameOverScene.ts
Normal file
43
game/src/scenes/GameOverScene.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import Phaser from 'phaser'
|
||||
|
||||
export default class PlayScene extends Phaser.Scene {
|
||||
|
||||
constructor() {
|
||||
super('game-over-scene')
|
||||
}
|
||||
|
||||
preload() {
|
||||
this.load.image('phaser-logo', 'assets/img/phaser3-logo.png')
|
||||
this.load.image('hs3-logo', 'assets/img/hs3-logo.png')
|
||||
}
|
||||
|
||||
create(data) {
|
||||
console.log("Show end screen with data:", data)
|
||||
|
||||
this.add.image(250, 550, 'phaser-logo').setScale(0.5)
|
||||
this.add.image(550, 550, 'hs3-logo').setScale(0.5)
|
||||
|
||||
this.add.text(
|
||||
this.cameras.main.centerX,
|
||||
this.cameras.main.centerY - 100,
|
||||
"KONIEC GRY", {
|
||||
font: '64px Verdana',
|
||||
}).setOrigin(0.5, 0.5)
|
||||
|
||||
const rank = 0
|
||||
const pts = data.points || 0
|
||||
const lvl = data.level || 0
|
||||
const time = Math.ceil(data.elapsedTime || 0)
|
||||
|
||||
this.add.text(this.cameras.main.centerX, this.cameras.main.centerY, [
|
||||
"Miejsce w rankingu: #" + rank,
|
||||
"Punkty: " + pts,
|
||||
"Poziom: " + lvl,
|
||||
"Czas Gry: " + time + 's',
|
||||
], {
|
||||
font: '32px Verdana',
|
||||
align: 'center',
|
||||
color: 'cyan'
|
||||
}).setOrigin(0.5, 0.5)
|
||||
}
|
||||
}
|
||||
113
game/src/scenes/PlayScene.ts
Normal file
113
game/src/scenes/PlayScene.ts
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
import Phaser from 'phaser'
|
||||
import Ship from '../classes/Ship'
|
||||
import Asteroid from '../classes/Asteroid'
|
||||
import DifficultyManager from '../classes/DifficultyManager'
|
||||
|
||||
export default class PlayScene extends Phaser.Scene {
|
||||
readonly maxAsteroids = 70
|
||||
|
||||
player?: Ship
|
||||
rotFrames?: Phaser.Types.Animations.AnimationFrame[]
|
||||
asteroids?: Phaser.GameObjects.Group
|
||||
difficulty?: DifficultyManager
|
||||
points = 0
|
||||
progressLabel?: Phaser.GameObjects.Text
|
||||
background?: Phaser.GameObjects.Image
|
||||
backgroundOrder: number[] = []
|
||||
backgroundId = 0
|
||||
startTimestamp: number = 0
|
||||
auth: any
|
||||
|
||||
constructor() {
|
||||
super('play-scene')
|
||||
|
||||
this.backgroundOrder = []
|
||||
for (let i = 1; i < 10; ++i)
|
||||
this.backgroundOrder.push(i)
|
||||
Phaser.Utils.Array.Shuffle(this.backgroundOrder)
|
||||
}
|
||||
|
||||
preload() {
|
||||
for (let i = 1; i < 10; i++)
|
||||
this.load.image(`sky${i}`, `assets/img/nebula0${i}.png`)
|
||||
this.load.image('ship', 'assets/img/ship.png')
|
||||
this.load.image('bullet', 'assets/img/bullet.png')
|
||||
this.load.spritesheet('particles', 'assets/img/boom.png', { frameWidth: 192, frameHeight: 192 })
|
||||
this.load.multiatlas('asteroids', 'assets/img/asteroids.json', 'assets/img');
|
||||
}
|
||||
|
||||
create(data) {
|
||||
console.log("Started game with", data)
|
||||
this.auth = data
|
||||
|
||||
Asteroid.createAnimations(this)
|
||||
this.difficulty = new DifficultyManager(this)
|
||||
this.events.on('getpoint', this.updateLabel, this)
|
||||
this.events.on('lvlup', this.updateLabel, this)
|
||||
this.events.on('lvlup', this.changeBackground, this)
|
||||
this.events.on('ship:gothit', this.updateLabel, this)
|
||||
this.events.on('ship:destroyed', this.gameOver, this)
|
||||
|
||||
this.background = this.add.image(400, 300, 'sky1')
|
||||
this.asteroids = this.add.group()
|
||||
this.player = new Ship(this)
|
||||
this.progressLabel = this.add.text(5, 5, "", {
|
||||
font: '32px Verdana',
|
||||
color: 'cyan'
|
||||
})
|
||||
this.progressLabel.setDepth(1)
|
||||
|
||||
this.startTimestamp = this.time.now
|
||||
this.changeBackground()
|
||||
this.updateLabel()
|
||||
this.hookupCollisions()
|
||||
}
|
||||
|
||||
gameOver() {
|
||||
console.log("%cU ded", "color:red")
|
||||
console.log("points: ", this.difficulty!.getPoints())
|
||||
this.scene.start('game-over-scene', {
|
||||
points: this.difficulty!.getPoints(),
|
||||
level: this.difficulty!.getLevel(),
|
||||
elapsedTime: (this.time.now - this.startTimestamp) / 1000
|
||||
})
|
||||
}
|
||||
|
||||
changeBackground() {
|
||||
const currentId = this.backgroundOrder[this.backgroundId]
|
||||
const key = 'sky' + currentId.toString()
|
||||
|
||||
this.background!.setTexture(key)
|
||||
this.backgroundId = (++this.backgroundId) % this.backgroundOrder.length
|
||||
}
|
||||
|
||||
spawnAsteroid() {
|
||||
if (this.asteroids!.getLength() < this.difficulty!.getMaxAsteroids())
|
||||
this.asteroids!.add(new Asteroid(this))
|
||||
}
|
||||
|
||||
updateLabel() {
|
||||
const lvl = this.difficulty!.getLevel()
|
||||
const pts = this.difficulty!.getPoints()
|
||||
const lives = this.player!.life
|
||||
|
||||
const str = `Level: ${lvl}\tPoints: ${pts}\tHP: ${lives}`
|
||||
this.progressLabel!.text = str
|
||||
}
|
||||
|
||||
hookupCollisions() {
|
||||
// player - asteroids
|
||||
this.physics.add.overlap(
|
||||
this.player!, this.asteroids!, // colliders
|
||||
this.player!.gotHit, // callback
|
||||
undefined, // callback filter
|
||||
this.player // 'this' for callback
|
||||
)
|
||||
|
||||
// bullets - asteroids
|
||||
this.physics.add.overlap(
|
||||
this.asteroids!, this.player!.bullets,
|
||||
Asteroid.prototype.gotHit
|
||||
)
|
||||
}
|
||||
}
|
||||
40
game/src/scenes/StartScene.ts
Normal file
40
game/src/scenes/StartScene.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import Phaser from 'phaser'
|
||||
|
||||
export default class StartScene extends Phaser.Scene {
|
||||
|
||||
constructor() {
|
||||
super('start-scene')
|
||||
}
|
||||
|
||||
preload() {
|
||||
this.load.image('phaser-logo', 'assets/img/phaser3-logo.png')
|
||||
this.load.image('hs3-logo', 'assets/img/hs3-logo.png')
|
||||
}
|
||||
|
||||
create() {
|
||||
this.add.image(250, 550, 'phaser-logo').setScale(0.5)
|
||||
this.add.image(550, 550, 'hs3-logo').setScale(0.5)
|
||||
|
||||
this.add.text(
|
||||
this.cameras.main.centerX,
|
||||
this.cameras.main.centerY - 100,
|
||||
"SPACE SMASHER 9001!", {
|
||||
font: '64px Verdana',
|
||||
}).setOrigin(0.5, 0.5)
|
||||
|
||||
this.add.text(this.cameras.main.centerX, this.cameras.main.centerY, [
|
||||
"Naciśnij przycisk aby zacząć",
|
||||
"",
|
||||
"Zaloguj się przed rozpoczęciem gry, aby zachować rekord",
|
||||
"albo graj jako gość (bez rankingu)"
|
||||
], {
|
||||
font: '21px Verdana',
|
||||
align: 'center',
|
||||
color: 'cyan'
|
||||
}).setOrigin(0.5, 0.5)
|
||||
|
||||
this.input.on('pointerup', () => {
|
||||
this.scene.start('play-scene', window.myStuff);
|
||||
});
|
||||
}
|
||||
}
|
||||
31
game/src/style.css
Normal file
31
game/src/style.css
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
html,body{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
background-color: black;
|
||||
font-family: "Verdana", "Geneva", "Tahoma", "sans-serif";
|
||||
}
|
||||
|
||||
body {
|
||||
background-image: url('../public/assets/img/stars.png');
|
||||
}
|
||||
|
||||
.bar {
|
||||
width: 100%;
|
||||
background-color: aqua;
|
||||
width: 800px;
|
||||
margin:auto;
|
||||
margin-bottom: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.key {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: block;
|
||||
width: 800px;
|
||||
margin: auto;
|
||||
box-shadow: 0 0 35px rgba(0,255,255,0.3);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue