Skip to content

Commit

Permalink
Merge branch 'main' of github.com:Chocobois/TurtleTrampoline
Browse files Browse the repository at this point in the history
  • Loading branch information
Golen87 committed Nov 19, 2023
2 parents 103e555 + 72258d6 commit f8ffa32
Show file tree
Hide file tree
Showing 7 changed files with 290 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/assets/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const audios: Audio[] = [
music("title", "m_main_menu"),
music("first", "m_first"),
sound("tree/rustle", "t_rustle", 0.5),
sound("turtle/score", "score", 0.5),
];

/* Fonts */
Expand Down
Binary file added src/assets/sounds/turtle/score.mp3
Binary file not shown.
194 changes: 194 additions & 0 deletions src/components/TextParticle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
import { GameScene } from "../scenes/GameScene";

export interface TextParticleEffects {
move?: {
moveSpeed?: number,
direction?: number,
}
wave?: {
enable: boolean,
waveSpeed?: number,
waveAngle?: number,
waveAmplitude?: number,
},
fadeOut?: {
enable: boolean,
baseOpacity?: number,
},
}

export interface TextParticleData {
textObject: Phaser.GameObjects.Text,
elapsedTime: number,
lifespan: number,
origin: Phaser.Math.Vector2,
effects: TextParticleEffects,
}

type CreateTextOptions = [
x: number, y: number, size: number, color: string, text: string
]

const ONE_OVER_TWO_PI = 1 / Phaser.Math.PI2;

export class TextParticle extends Phaser.GameObjects.Container {
public scene: GameScene;
public textParticles: Array<TextParticleData>;

constructor(scene: GameScene) {
super(scene, 0, 0);
this.scene = scene;
scene.add.existing(this);

this.textParticles = [];
this.DEFAULT_MOVE_SPEED = 1;
this.DEFAULT_WAVE_SPEED = 5;
this.DEFAULT_WAVE_AMPLITUDE = 2/3;

this.DEAFULT_EFFECTS = {
fadeOut: {enable: true},
move: { moveSpeed: this.DEFAULT_MOVE_SPEED },
wave: { waveAmplitude: this.DEFAULT_WAVE_AMPLITUDE,
enable: true,
},
}

this.DEAFULT_EFFECTS_HALF = {
fadeOut: {enable: true},
move: { moveSpeed: this.DEFAULT_MOVE_SPEED / 2 },
wave: { waveAmplitude: this.DEFAULT_WAVE_AMPLITUDE / 2,
enable: true,
},
}
}

public DEFAULT_MOVE_SPEED: number;
public DEFAULT_WAVE_SPEED: number;
public DEFAULT_WAVE_AMPLITUDE: number;
public readonly DEFAULT_MOVE_ANGLE: number = Phaser.Math.DegToRad(-45);
public readonly DEFAULT_WAVE_ANGLE: number = Phaser.Math.DegToRad(180);

public DEAFULT_EFFECTS: TextParticleEffects;
public DEAFULT_EFFECTS_HALF: TextParticleEffects;


update(time: number, delta: number) {
const extraTime = delta / 1000;
let removeFlag = false;

this.textParticles.forEach(data => {
data.elapsedTime += extraTime;

if (data.elapsedTime > data.lifespan) {
removeFlag = true;
data.textObject.destroy()
data.elapsedTime = -1;
}

else {
const effects = {
move: (data.effects.move?.moveSpeed ?? 0) != 0,
wave: data.effects.wave?.enable,
fade: data.effects.fadeOut?.enable,
}

const { x, y } = data.origin;
let newPosition = new Phaser.Math.Vector2(x, y);
let log: string[] = [];

const textSize = data.textObject.getTextMetrics().fontSize * 2/3;

if (effects.move) {
const moveOffset = new Phaser.Math.Vector2(0, 0).setToPolar(
data.effects.move?.direction ?? this.DEFAULT_MOVE_ANGLE,
data.elapsedTime * (data.effects.move?.moveSpeed ?? this.DEFAULT_MOVE_SPEED) * textSize,
);
// log = [...log, "moveOffset", moveOffset.x.toFixed(2), moveOffset.y.toFixed(2)];
newPosition.add(moveOffset);
}

if (effects.wave) {
const multiplier = ONE_OVER_TWO_PI * (data.effects.wave?.waveAmplitude ?? this.DEFAULT_WAVE_AMPLITUDE);

const phase = data.elapsedTime * (data.effects.wave?.waveSpeed ?? this.DEFAULT_WAVE_SPEED);
const amplitude = multiplier * textSize;

const waveOffset = new Phaser.Math.Vector2 ( amplitude * Math.sin(phase), 0 )
waveOffset.rotate(data.effects.wave?.waveAngle ?? this.DEFAULT_WAVE_ANGLE)

// log = [...log, "waveOffset", waveOffset.x.toFixed(2), waveOffset.y.toFixed(2)];
newPosition.add(waveOffset)
}

if (effects.wave || effects.move) {
data.textObject.setPosition(newPosition.x, newPosition.y)
}

if (effects.fade) {
const progress = data.elapsedTime / data.lifespan;
data.textObject.alpha = (data.effects.fadeOut?.baseOpacity ?? 1) * (1-progress);
}

// console.log(...log)
}
})

// Remove destroyed text from array

if (removeFlag) this.textParticles = this.textParticles.filter(
data => data.elapsedTime != -1
)
}

/**
* Register a new text as a text particle
* @param text Phaser Text object to use, or arguments for createText()
* @param lifespan Lifespan in seconds
* @param effects Object describing effects (move, fade, wave)
*/
push(text: Phaser.GameObjects.Text | CreateTextOptions, lifespan: number=1, effects: TextParticleEffects={
wave: {enable: false}, fadeOut: {enable: false}
}) {
const textObject = (text instanceof Phaser.GameObjects.Text)
? text
: this.scene.createText(...text);

/* const origin = (text instanceof Phaser.GameObjects.Text)
? { x: text.x, y: text.y }
: { x: text[0], y: text[1] }; */

const origin = { x: textObject.x, y: textObject.y };
Object.freeze(origin);

const effectDefaults = {
move: { moveSpeed: this.DEFAULT_MOVE_SPEED, direction: this.DEFAULT_MOVE_ANGLE },
fadeOut: { enable: false, baseOpacity: "alpha" in text ? text.alpha : 1 },
wave: {
enable: false,
waveSpeed: this.DEFAULT_WAVE_SPEED,
waveAngle: this.DEFAULT_WAVE_ANGLE,
waveAmplitude: this.DEFAULT_WAVE_AMPLITUDE,
},
};
this.textParticles.push({
textObject,
elapsedTime: 0,
lifespan, effects: {...effectDefaults, ...effects},
origin: new Phaser.Math.Vector2 (origin),
});
}

getArray() {
return this.textParticles;
}

die() {
let removeCounter = 0;
this.textParticles.forEach(particle => {
particle.textObject.destroy();
removeCounter++;
})
this.textParticles = [];
return removeCounter;
}
}
39 changes: 38 additions & 1 deletion src/components/Turtle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const ACCELERATION = 150;
const MAX_SPEED = 400;
const FRICTION = 0.7;
const TAPPING_TIMER = 200; // ms
const MAX_FADE = 2000;
console.assert(
ACCELERATION / (1 - FRICTION) >= MAX_SPEED,
"Max speed unreachable"
Expand Down Expand Up @@ -35,10 +36,15 @@ export class Turtle extends Button {
private walkTarget: Phaser.Geom.Point;
private walkTimer: number;

//Scor
//Score
private baseScore: number;
private multiplier: number;

//Fade/leaving variables
private fadeTimer: number;
private leaving: boolean;
private deleteFlag: boolean;

// Jumping
private trampoline: Trampoline;
private feetOffset: number;
Expand Down Expand Up @@ -100,6 +106,9 @@ export class Turtle extends Button {
this.bounceCount = 0;
this.baseScore = 50+(Math.random()*100);
this.multiplier = 1.0;
this.leaving = false;
this.fadeTimer = 0;
this.deleteFlag = false;

/* Input */
this.dragOffset = new Phaser.Math.Vector2();
Expand All @@ -115,6 +124,7 @@ export class Turtle extends Button {
// Trampoline
if (this.isOnTrampoline) {
// Bounce on trampoline rug
//this.scene.addScore(1);
if (
this.physicsPosition.y + this.feetOffset >=
this.trampoline.zone.bottom
Expand All @@ -127,6 +137,7 @@ export class Turtle extends Button {

if (jumpSpeed > maxSpeed - 10) {
this.bounceCount += 1;
//this.scene.addScore(1);
this.multiplier += 0.05;
this.scene.sound.play("t_rustle",{ volume: 0.5 });
this.emit("bounce");
Expand Down Expand Up @@ -165,6 +176,20 @@ export class Turtle extends Button {
const walkingSpeed = 1.0;
this.physicsVelocity.x += walkingSpeed * Math.sign(distance);
}

if(this.multiplier > 1) {
if(this.fadeTimer > 0 && this.leaving) {
this.fadeTimer -= delta;
if(this.fadeTimer <= 0)
{
this.fadeTimer = 0;
this.deleteFlag = true;
}
this.sprite.setAlpha(this.fadeTimer/MAX_FADE);
} else if (!this.leaving) {
this.turtleLeave();
}
}
}

// Friction
Expand Down Expand Up @@ -263,6 +288,18 @@ export class Turtle extends Button {
this.sprite.setDepth(depth);
}


turtleLeave(){
this.leaving = true;
this.disableInteractive();
this.sprite.disableInteractive();
this.fadeTimer = MAX_FADE;
let s = Math.round(this.multiplier*this.baseScore);
this.scene.addScore(s);
this.scene.sound.play("score", {volume: 1.0});
this.scene.addTextParticle(this.x+this.sprite.x, this.y+this.sprite.y-70, "green", `+ $` + `${s}`, 80);
}

/* Jumping */

updateFeetOffset() {
Expand Down
16 changes: 15 additions & 1 deletion src/components/UI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export class UI extends Phaser.GameObjects.Container {
private panel: Phaser.GameObjects.Container;
private background: Phaser.GameObjects.Image;
private text: Phaser.GameObjects.Text;
private score: number;

constructor(scene: GameScene) {
super(scene, 0, 0);
Expand All @@ -27,17 +28,30 @@ export class UI extends Phaser.GameObjects.Container {
y: 0,
size: 60,
color: "#FFFFFF",
text: "Score: 123",
text: "Score: 0",
});
this.text.setStroke("black", 8);
this.text.setOrigin(0, 0.5);
this.panel.add(this.text);
this.score = 0;


this.panel.setPosition(
this.scene.W - this.background.displayWidth / 2 - 30,
this.background.displayHeight / 2 + 30
);
}

addScore(score: number)
{
this.score += score;
this.text.setText('Score: ' + this.score.toString());
}

setScore(score: number)
{
this.score = score;
this.text.setText('Score: ' + this.score.toString());
}
update(time: number, delta: number) {}
}
9 changes: 9 additions & 0 deletions src/scenes/BaseScene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,15 @@ export class BaseScene extends Phaser.Scene {
.setPadding(2);
}

// Creates Phaser text object
createText(x: number=0, y: number=0, size: number=20, color: string="#FFF", text: string=""): Phaser.GameObjects.Text {
return this.add.text(x, y, text, {
fontFamily: "Game Font",
fontSize: Math.max(size*10, 1) + "px",
color: color
}).setLineSpacing(0.4*size).setPadding(2).setScale(0.1);
}

// The image keeps its aspect ratio, but is resized to fit within the given dimension
fitToScreen(image: Phaser.GameObjects.Image): void {
image.setScale(Math.max(this.W / image.width, this.H / image.height));
Expand Down
Loading

0 comments on commit f8ffa32

Please sign in to comment.