From 452dd58472706aab37ddf28312a0ca0241f0cb27 Mon Sep 17 00:00:00 2001
From: TitanPlayz <118145727+TitanPlayz100@users.noreply.github.com>
Date: Tue, 15 Oct 2024 16:49:07 +1100
Subject: [PATCH 1/6] clear delay
---
index.html | 1 +
info.md | 46 ++++++++++++++++++++++++++---------
src/data/defaultSettings.json | 15 ++++++------
src/mechanics/clearlines.js | 2 ++
src/mechanics/locking.js | 22 +++++++++++------
src/movement/controls.js | 2 +-
6 files changed, 61 insertions(+), 27 deletions(-)
diff --git a/index.html b/index.html
index 058ad03..63a9327 100644
--- a/index.html
+++ b/index.html
@@ -182,6 +182,7 @@
Teti
+
diff --git a/info.md b/info.md
index 6ee1f5a..89123ee 100644
--- a/info.md
+++ b/info.md
@@ -16,11 +16,11 @@ This project started out as a learning experience, because surprisingly it was m
## Acknowledgements
Thanks [existancepy](https://github.com/existancepy) for all the fixes.
-Thanks [ItzBlack6093](https://github.com/ItzBlack6093) for adding TGM Race mode and other fixes.
+Thanks [ItzBlack6093](https://github.com/ItzBlack6093) for adding many modes and fixes.
Feel free to contribute with features and fixes, and open issues.
-Design inspired by [Strangelinx's 'blocks'](https://strangelinx.github.io/blocks/) and [Tetra Legends.](https://tetralegend.app)
+Design inspired by [Strangelinx's 'blocks'](https://strangelinx.github.io/blocks/) and [Tetra Legends.](https://tetralegends.app)
Icons from [The Noun Project.](https://thenounproject.com)
Sound effects from [TETR.IO.](https://tetr.io)
Skins from [YHF](https://you.have.fail/ed/at/tetrioplus/)
@@ -67,10 +67,28 @@ Skins from [YHF](https://you.have.fail/ed/at/tetrioplus/)
## TODO list
Things that I am working on based on other changes
-- wow finished
+- ready set go start option
+- arcade mode
+
+Maybe:
+- cooler action text (maybe if i switch to pixijs then i can make text better)
+
+Future thoughts (honestly only if i have time):
+- I honestly might want to break my rule and start using a framework for rendering.
+ - (turns out pixijs is much better for games than canvas 2d, and howler for audio)
+- I have mixed feelings, because this would make the project technically no longer purely made by me (though the info page is a bit iffy)
+- Maybe I don't care and will switch anyway, and maybe in the end it will pay off.
+- this would make my most recent changes irrelivent
+ - such as piece flash and reset animation cause i have to redo them in pixi
+ - in the future itll probably pay off
+***
## Updates
+#### v1.3.3
+- Thanks to itzblack for the Zenith Tower mode
+- added option for line clear delay
+
#### v1.3.2
- reset animation
- toggles with stride mode
@@ -80,7 +98,7 @@ Things that I am working on based on other changes
- added notifications
- displays errors
- shows export and import messages
-- removed assets loading screen, cause it was unecessary
+- removed assets loading screen, cause it was unnecessary
- added different grid patterns
#### v1.3.1
@@ -159,8 +177,8 @@ Things that I am working on based on other changes
- can easily add custom gamemodes now using gamemodes JSON
- competitive mode
- sets certain gamerules, disables custom game settings
- - PBs are onyl saved when used
-- seperated goals into its own menu
+ - PBs are only saved when used
+- separated goals into its own menu
- view pbs in competitive mode menu
### v1.2.0 => COMPETITIVE MODE
@@ -203,8 +221,6 @@ Things that I am working on based on other changes
***
## Feature Wishlist
Future wants for game, kinda ordered by ease and desire for feature
-- ready set go start option
-- cooler action text
- finesse detection
- allow importing tetrio settings and custom game files
- small guide on essential things for game
@@ -212,14 +228,20 @@ Future wants for game, kinda ordered by ease and desire for feature
- WIKI for technical docs about project
- glossary of useful terms
- more rotation systems (ars, trs, srs/srsX, none)
+- more bag systems (pure random, nes random, 14 bag, 7+2 bag)
- replay functionality (either save gamestate or save keystrokes idk yet)
+ - statistics graph
- more unique gamemodes (techmino styled)
- misdrop remover mode
- holdless and next queueless gamemode kinda like qp2 cards
- colourblind gamemode
-- guide like progression thing? using custom boards (kinda like tetris tres bien)
+- guide like progression using custom maps
+ - maybe like tetris tres bien
- achievements, progression tree
-- maybe play around with server api stuff, like adding a leaderboard or connecting tetrio stats
+ - the jstris map creator looks really nice
+ - could have user made maps section as well
+- maybe play around with api stuff
+ - leaderboards
+ - connecting tetrio stats
- touch settings
-- bot to play against
-- statistics graph
\ No newline at end of file
+- bot to play against
\ No newline at end of file
diff --git a/src/data/defaultSettings.json b/src/data/defaultSettings.json
index eb5926c..ade8d14 100644
--- a/src/data/defaultSettings.json
+++ b/src/data/defaultSettings.json
@@ -27,7 +27,14 @@
"preserveARR": true,
"allowHold": true,
"infiniteHold": true,
+ "clearDelay": 0,
"gamemode": "sprint",
+ "allspin": true,
+ "allspinminis": true,
+ "history": true,
+ "competitiveMode": false,
+ "sidebar": ["time", "apm", "pps"],
+ "stride": false,
"requiredLines": 40,
"timeLimit": 120,
"requiredAttack": 40,
@@ -37,13 +44,7 @@
"allowQueueModify": true,
"lookAheadPieces": 3,
"raceTarget": 500,
- "requiredAltitude": 1650,
- "allspin": true,
- "allspinminis": true,
- "history": true,
- "competitiveMode": false,
- "sidebar": ["time", "apm", "pps"],
- "stride": false
+ "requiredAltitude": 1650
},
"control": {
"rightKey": "ArrowRight",
diff --git a/src/mechanics/clearlines.js b/src/mechanics/clearlines.js
index 15eeab1..3964865 100644
--- a/src/mechanics/clearlines.js
+++ b/src/mechanics/clearlines.js
@@ -37,6 +37,7 @@ export class ClearLines {
if (clearRows.length > 0) this.game.renderer.bounceBoard("DOWN");
this.game.particles.spawnParticles(0, Math.min(...clearRows), "clear")
this.processLineClear(removedGarbage, clearRows);
+ return clearRows.length;
}
clearRow(rowNumber) {
@@ -66,6 +67,7 @@ export class ClearLines {
this.manageGarbageSent(damage);
this.game.zenith.AwardLines(damage);
+ if (linecount == 1) this.game.zenith.AwardLines(1);
// render action text
if (mech.isAllspin) damagetype = damagetype.replace("Tspin ", this.game.falling.piece.name + " spin ");
this.game.renderer.renderActionText(damagetype, isBTB, isPC, damage, linecount);
diff --git a/src/mechanics/locking.js b/src/mechanics/locking.js
index c6fe641..1300be0 100644
--- a/src/mechanics/locking.js
+++ b/src/mechanics/locking.js
@@ -4,7 +4,7 @@ export class LockPiece {
divLockTimer = document.getElementById("lockTimer");
divLockCounter = document.getElementById("lockCounter");
lockCount;
- timings = { lockdelay: 0, lockingTimer: 0 }
+ timings = { lockdelay: 0, lockingTimer: 0, clearDelay: 0 }
startTime = 0;
remaining = 0;
@@ -73,16 +73,18 @@ export class LockPiece {
const lockCoords = this.game.mechanics.board.getMinos("A");
this.game.boardrender.justPlacedCoords = lockCoords;
this.game.boardrender.justPlacedAlpha = 1;
-
+
lockCoords.forEach(([x, y]) => {
- this.game.boardrender.flashTimes.push({ c:[x, y], t: 15 })
+ this.game.boardrender.flashTimes.push({ c: [x, y], t: 15 })
this.game.mechanics.board.rmValue([x, y], "A");
this.game.mechanics.board.addValFront([x, y], "S");
});
+
this.game.mechanics.locking.clearLockDelay();
clearInterval(this.game.gravityTimer);
- this.game.mechanics.clear.clearLines(lockCoords);
- this.game.endGame( // stopped overlap next
+ const cleared = this.game.mechanics.clear.clearLines(lockCoords);
+
+ this.game.endGame( // check stopped overlap next
this.game.mechanics.checkDeath(
this.game.mechanics.board.getMinos("S"),
this.game.mechanics.board.getMinos("NP")
@@ -101,12 +103,18 @@ export class LockPiece {
this.game.mechanics.isMini = false;
this.game.falling.moved = false;
if (this.game.stats.level % 100 != 99 && this.game.stats.level != this.game.settings.game.raceTarget - 1) this.game.stats.level++;
+
const xvals = [...new Set(lockCoords.map(([x, y]) => x))];
const yval = Math.min(...lockCoords.map(([x, y]) => y));
this.game.particles.spawnParticles(Math.min(...xvals) + 1, yval, "lock", xvals.length);
- this.game.mechanics.spawnPiece(this.game.bag.randomiser());
- this.game.history.save();
this.game.renderer.renderDanger();
+
+ const delay = (cleared > 0) ? this.game.settings.game.clearDelay : 0;
+ this.timings.clearDelay = setTimeout(() => {
+ this.game.mechanics.spawnPiece(this.game.bag.randomiser());
+ this.game.history.save();
+ this.timings.clearDelay = 0;
+ }, delay);
}
clearLockDelay(clearCount = true) {
diff --git a/src/movement/controls.js b/src/movement/controls.js
index 0d4346e..fc44288 100644
--- a/src/movement/controls.js
+++ b/src/movement/controls.js
@@ -25,7 +25,7 @@ export class Controls {
if (key == this.menuKey) this.game.menuactions.toggleDialog();
else if (key == keys.editMenuKey) this.game.menuactions.openEditMenu();
- if (this.game.modals.open || this.game.modals.closing) return;
+ if (this.game.modals.open || this.game.modals.closing || this.game.mechanics.locking.timings.clearDelay != 0) return;
if (event.key != this.menuKey && !this.game.started) this.moves.firstMovement();
if (key == keys.resetKey) this.retry(true);
if (this.game.ended) return;
From e09a5523f66bfa784835a66f0e0ec38a32162ebf Mon Sep 17 00:00:00 2001
From: TitanPlayz <118145727+TitanPlayz100@users.noreply.github.com>
Date: Thu, 17 Oct 2024 21:00:36 +1100
Subject: [PATCH 2/6] Completely changed all rendering to use PIXIjs Changed
board, next queue, hold queue, and particles to run using pixijs in webgl,
making it much faster. Reimplemented much of the logic for rendering to be
more readable.
---
.github/workflows/main.yml | 15 +-
.gitignore | 5 +-
README.md | 18 +-
assets/particle.png | Bin 0 -> 171 bytes
index.html | 5 +-
info.md | 23 +-
src/data/blocksprites.json | 20 ++
src/data/defaultSettings.json | 4 +-
src/display/boardEffects.js | 6 +-
src/display/particles.js | 139 +++++++------
src/display/pixirender.js | 380 ++++++++++++++++++++++++++++++++++
src/display/renderBoard.js | 160 --------------
src/display/renderer.js | 152 ++------------
src/features/sounds.js | 4 +-
src/game.js | 20 +-
src/main.js | 22 +-
src/mechanics/board.js | 10 +-
src/mechanics/clearlines.js | 2 +-
src/mechanics/locking.js | 8 +-
src/menus/modals.js | 2 +-
src/movement/controls.js | 7 +-
src/movement/movement.js | 4 +-
styles/style.css | 4 +-
23 files changed, 581 insertions(+), 429 deletions(-)
create mode 100644 assets/particle.png
create mode 100644 src/data/blocksprites.json
create mode 100644 src/display/pixirender.js
delete mode 100644 src/display/renderBoard.js
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 737f7cb..0fbb298 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -3,8 +3,6 @@ name: 'Publish Tauri App'
on:
workflow_dispatch:
-# This workflow will trigger on each push to the `release` branch to create or update a GitHub release, build your app, and upload the artifacts to the release.
-
jobs:
publish-tauri:
permissions:
@@ -17,7 +15,7 @@ jobs:
# args: '--target aarch64-apple-darwin'
#- platform: 'macos-latest' # for Intel based macs.
# args: '--target x86_64-apple-darwin'
- - platform: 'ubuntu-22.04' # for Tauri v1 you could replace this with ubuntu-20.04.
+ - platform: 'ubuntu-20.04'
args: ''
- platform: 'windows-latest'
args: ''
@@ -34,17 +32,13 @@ jobs:
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
- # Those targets are only used on macos runners so it's in an `if` to slightly speed up windows and linux builds.
targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
- name: install dependencies (ubuntu only)
- if: matrix.platform == 'ubuntu-22.04' # This must match the platform value defined above.
+ if: matrix.platform == 'ubuntu-20.04'
run: |
sudo apt-get update
- sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
- # webkitgtk 4.0 is for Tauri v1 - webkitgtk 4.1 is for Tauri v2.
- # You can remove the one that doesn't apply to your app to speed up the workflow a bit.
-
+ sudo apt-get install -y libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- run: |
mkdir -p tauri/src
@@ -52,6 +46,7 @@ jobs:
cp -r assets/ tauri/src/
cp -r styles/ tauri/src/
cp -r src/ tauri/src/
+ cp -r lib/ tauri/src/
cd tauri
npm install
@@ -59,7 +54,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
- tagName: app-v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version.
+ tagName: app-v__VERSION__ # automatically replaces \_\_VERSION\_\_ with the app version
releaseName: 'App v__VERSION__'
releaseBody: 'See the assets to download this version and install.'
releaseDraft: true
diff --git a/.gitignore b/.gitignore
index 414c49a..4397437 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
.vscode/
-package-lock.json
-Cargo.lock
\ No newline at end of file
+Cargo.lock
+*.d.ts
+jsconfig.json
\ No newline at end of file
diff --git a/README.md b/README.md
index 60af4c1..6a797a4 100644
--- a/README.md
+++ b/README.md
@@ -8,8 +8,6 @@ The info page can be found [here](https://titanplayz100.github.io/teti/info.html
> Firefox is not supported (due to import assertions)
## Desktop App
-### NEW!
-
Releases are now run through a workflow. They are **up to date** and contain all the latest features.
App build using Tauri, feel free to open issues and PRs.
@@ -35,7 +33,7 @@ gamemodes = {
}
```
-Add functionality mainly in `features/modes.js`.
+Add functionality mainly in `features/modes.js`.
You can modify existing modules as well from other files
### Adding Audio (sfxlist.json)
@@ -48,3 +46,17 @@ You can modify existing modules as well from other files
}
```
Use with `this.game.sounds.playSound()`
+
+
+## Types for PIXIjs
+Workaround to use types when using pixijs imported through script tag:
+- download [pixi.js.d.ts](https://github.com/pixijs/pixijs/releases) from pixijs repo and place file in /src
+- setup jsconfig.json to automatically detect pixi.js.d.ts for types
+
+```json
+{
+ "typeAcquisition": {
+ "include": ["pixi.js.d.ts"]
+ }
+}
+```
\ No newline at end of file
diff --git a/assets/particle.png b/assets/particle.png
new file mode 100644
index 0000000000000000000000000000000000000000..3021288d721a5d4561229ab3773e6ea2159ff59c
GIT binary patch
literal 171
zcmeAS@N?(olHy`uVBq!ia0vp^EFjFn3?!rPH~Ru9#^NA%C&rs6b?Si}&H|6fVg?3o
zVGw3ym^DWNC@3A^6XNzopr0L)51oB#j-
literal 0
HcmV?d00001
diff --git a/index.html b/index.html
index 63a9327..b8fbb1a 100644
--- a/index.html
+++ b/index.html
@@ -10,6 +10,7 @@
+
@@ -18,7 +19,7 @@
⚠ GO DOWN
-
+
@@ -146,7 +147,7 @@ Teti
-
+
diff --git a/info.md b/info.md
index 89123ee..18e2262 100644
--- a/info.md
+++ b/info.md
@@ -69,22 +69,21 @@ Skins from [YHF](https://you.have.fail/ed/at/tetrioplus/)
Things that I am working on based on other changes
- ready set go start option
- arcade mode
-
-Maybe:
-- cooler action text (maybe if i switch to pixijs then i can make text better)
-
-Future thoughts (honestly only if i have time):
-- I honestly might want to break my rule and start using a framework for rendering.
- - (turns out pixijs is much better for games than canvas 2d, and howler for audio)
-- I have mixed feelings, because this would make the project technically no longer purely made by me (though the info page is a bit iffy)
-- Maybe I don't care and will switch anyway, and maybe in the end it will pay off.
-- this would make my most recent changes irrelivent
- - such as piece flash and reset animation cause i have to redo them in pixi
- - in the future itll probably pay off
+- cooler action text
***
## Updates
+#### v1.3.4 => PIXIjs
+- COMPLETE REWRITE OF ALL GRAPHICS
+- Everything is now rendered through pixijs
+ - this includes the board, next queue, hold queue, and particles
+ - ye turns out there is a high learning curve with pixi (i lost it several times)
+ - everything should now be much more performant and smooth yay
+
+- some things were changed due to this
+ - need to add border colour back
+
#### v1.3.3
- Thanks to itzblack for the Zenith Tower mode
- added option for line clear delay
diff --git a/src/data/blocksprites.json b/src/data/blocksprites.json
new file mode 100644
index 0000000..7d967f9
--- /dev/null
+++ b/src/data/blocksprites.json
@@ -0,0 +1,20 @@
+{
+ "frames": {
+ "z": { "frame": { "x": 0, "y": 0, "w": 30, "h": 30 } },
+ "l": { "frame": { "x": 31, "y": 0, "w": 30, "h": 30 } },
+ "o": { "frame": { "x": 62, "y": 0, "w": 30, "h": 30 } },
+ "s": { "frame": { "x": 93, "y": 0, "w": 30, "h": 30 } },
+ "i": { "frame": { "x": 124, "y": 0, "w": 30, "h": 30 } },
+ "j": { "frame": { "x": 155, "y": 0, "w": 30, "h": 30 } },
+ "t": { "frame": { "x": 186, "y": 0, "w": 30, "h": 30 } },
+ "shadow": { "frame": { "x": 217, "y": 0, "w": 30, "h": 30 } },
+ "hold": { "frame": { "x": 248, "y": 0, "w": 30, "h": 30 } },
+ "g": { "frame": { "x": 279, "y": 0, "w": 30, "h": 30 } },
+ "darkg": { "frame": { "x": 310, "y": 0, "w": 30, "h": 30 } },
+ "topout": { "frame": { "x": 341, "y": 0, "w": 30, "h": 30 } }
+ },
+ "meta": {
+ "size": { "w": 372, "h": 30 },
+ "scale": "1"
+ }
+}
\ No newline at end of file
diff --git a/src/data/defaultSettings.json b/src/data/defaultSettings.json
index ade8d14..5b69262 100644
--- a/src/data/defaultSettings.json
+++ b/src/data/defaultSettings.json
@@ -3,7 +3,7 @@
"background": "#080B0C",
"boardOpacity": 100,
"showGrid": true,
- "gridopacity": 20,
+ "gridopacity": 30,
"gridType":"round",
"shadowOpacity": 20,
"boardHeight": 80,
@@ -11,7 +11,7 @@
"colouredQueues": true,
"lockBar": true,
"rainbowPB": true,
- "boardBounce": 1,
+ "boardBounce": 2,
"outoffocus": true,
"particles":true,
"particleVolume": 60,
diff --git a/src/display/boardEffects.js b/src/display/boardEffects.js
index e11887a..4298107 100644
--- a/src/display/boardEffects.js
+++ b/src/display/boardEffects.js
@@ -6,8 +6,8 @@ export class BoardEffects {
Y = 0;
dX = 0;
dY = 0;
- friction = 0.75;
- springConstant = 0.02;
+ friction = 0.7;
+ springConstant = 0.015;
targetX = 0;
targetY = 0;
R = 0;
@@ -51,6 +51,7 @@ export class BoardEffects {
if (this.X != 0 || this.Y != 0) {
this.divBoard.style.translate = `${this.X}px ${this.Y}px`
+ this.game.pixi.app.canvas.style.translate = `${this.X}px ${this.Y}px`
}
}
@@ -66,6 +67,7 @@ export class BoardEffects {
if (this.R != 0) {
this.divBoard.style.rotate = `${this.R}deg`
+ this.game.pixi.app.canvas.style.rotate = `${this.R}deg`
}
}
diff --git a/src/display/particles.js b/src/display/particles.js
index f87b165..ca5dace 100644
--- a/src/display/particles.js
+++ b/src/display/particles.js
@@ -1,11 +1,12 @@
import { Game } from "../game.js";
class Point {
- constructor(particleInfo, ctx) {
- const { x, y, colour, size, life, dx, dy, sway, xF, yF, swayF, gravity, twinkle, twinkleTime } = particleInfo;
+ constructor(particleInfo, particleInstance) {
+ const { x, y, colour, life, dx, dy, sway, xF, yF, swayF, gravity, twinkle, twinkleTime } = particleInfo;
this.x = x;
this.y = y;
- this.size = size;
+ this.maxSize = particleInstance.size;
+ this.size = this.maxSize;
this.colour = colour;
this.maxLife = life;
this.life = life;
@@ -19,15 +20,18 @@ class Point {
this.twinkle = twinkle ?? false;
this.twinkleTime = twinkleTime ?? this.life;
- this.ctx = ctx;
+ const particle = new PIXI.Sprite(particleInstance.texture);
+ this.particle = particle;
+ this.particle.tint = colour;
+ particleInstance.container.addChild(particle);
+ particleInstance.particles.push(this);
}
draw() {
- this.ctx.globalAlpha = Math.max(0, this.life / this.maxLife);
- this.ctx.fillStyle = this.colour;
- this.ctx.beginPath();
- this.ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
- this.ctx.fill();
+ this.particle.alpha = Math.max(0, this.life / this.maxLife);
+ this.particle.x = this.x;
+ this.particle.y = this.y;
+ this.particle.scale.set(0.5 * this.size)
}
update() {
@@ -38,11 +42,13 @@ class Point {
this.dy *= this.frictionY;
this.sway *= this.frictionSway
this.dy += this.gravity;
- if (this.twinkle && this.life < this.twinkleTime) this.size = Math.abs((Math.sin(this.life / 15))) * 2;
+ if (this.twinkle && this.life < this.twinkleTime)
+ this.size = Math.abs((Math.sin(this.life / 15))) * this.maxSize;
}
}
export class Particles {
+ /** @type {Point[]} */
particles = [];
/**
@@ -50,57 +56,60 @@ export class Particles {
*/
constructor(game) {
this.game = game;
- this.ctx = this.game.renderer.ctx;
}
initBoard() {
- this.boardWidth = this.game.renderer.boardWidth;
- this.boardHeight = this.game.renderer.boardHeight;
- this.minosize = this.game.boardrender.minoSize;
+ this.container = this.game.pixi.app.stage.getChildByLabel("particles");
+ }
+
+ async loadTexture() {
+ this.texture = await PIXI.Assets.load('./assets/particle.png');
}
spawnParticles(posX, posY, type, pieceWidth = 1, cw = false, colour = "white") {
- if (!this.game.settings.display.particles) return
+ if (!this.game.settings.display.particles) return;
+
+ const boardWidth = this.game.pixi.width;
+ const boardHeight = this.game.pixi.height * 2;
+ const minosize = this.game.pixi.minoSize;
+ const [x, y] = [posX * minosize, (40 - posY) * minosize];
this.volume = this.game.settings.display.particleVolume;
this.size = this.game.settings.display.particleSize;
- const [x, y] = [posX * this.minosize, (40 - posY) * this.minosize];
- if (type == "drop") this.creatDropParticles(x, y, colour, this.minosize * pieceWidth, -this.boardHeight);
- if (type == "lock") this.createLockParticles(x, y, colour, this.minosize * pieceWidth, 10);
- if (type == "clear") this.createClearParticles(x, y, colour, this.boardWidth, -10);
- if (type == "pc") this.createPCParticles(x, y, this.boardWidth, 10);
- if (type == "dangerboard") this.createDangerBoardParticles(x, this.boardHeight, colour, this.boardWidth, 10);
- if (type == "dangersides") this.createDangerSidesParticles(x, y, "red", this.boardWidth, 0, 1);
- if (type == "spin") this.createSpinParticles(x, y, colour, cw, this.minosize * pieceWidth, -this.minosize * pieceWidth);
- if (type == "spike") this.createSpikeParticles(x, this.boardHeight, colour, this.boardWidth, -this.boardHeight);
- if (type == "BTB") this.createBTBParticle(x, y, "gold", this.boardWidth, 0, this.boardHeight);
+ if (type == "drop") this.creatDropParticles(x, y, colour, minosize * pieceWidth, -boardHeight);
+ if (type == "lock") this.createLockParticles(x, y, colour, minosize * pieceWidth, 10);
+ if (type == "clear") this.createClearParticles(x, y, colour, boardWidth, -10);
+ if (type == "pc") this.createPCParticles(x, y, boardWidth, 10);
+ if (type == "dangerboard") this.createDangerBoardParticles(x, boardHeight, colour, boardWidth, 10);
+ if (type == "dangersides") this.createDangerSidesParticles(x, y, "red", boardWidth, 0, 1);
+ if (type == "spin") this.createSpinParticles(x, y, colour, cw, minosize * pieceWidth, -minosize * pieceWidth);
+ if (type == "spike") this.createSpikeParticles(x, boardHeight, colour, boardWidth, -boardHeight);
+ if (type == "BTB") this.createBTBParticle(x, y, "gold", boardWidth, 0, boardHeight);
}
creatDropParticles(x, y, colour, len, height) {
for (let i = 0; i < this.volume / 3; i++) {
- const posX = x + Math.random() * len - len / 2;
+ const posX = x + Math.random() * len
const posY = y + Math.random() * height / 2;
const life = Math.random() * 35 + 70;
- const dx = Math.random() * 1 - 0.5;
+ const dx = Math.random() * 0.8 - 0.2;
const dy = Math.random() * -1.2 - 2.4;
const sway = Math.random() * 0.04 - 0.02;
- const placeParticle = { x: posX, y: posY, colour, size: this.size, life, dx, dy, sway, xF: 0.95, yF: 0.95, swayF: 0.96 }
- const particle = new Point(placeParticle, this.ctx);
- this.particles.push(particle);
+ const placeParticle = { x: posX, y: posY, colour, life, dx, dy, sway, xF: 0.93, yF: 0.93, swayF: 0.93 }
+ new Point(placeParticle, this);
}
}
createLockParticles(x, y, colour, len, height) {
for (let i = 0; i < this.volume / 4; i++) {
- const posX = x + Math.random() * len - len / 2;
+ const posX = x + Math.random() * len;
const posY = y + Math.random() * height;
const life = Math.random() * 15 + 30;
- const dx = Math.random() * 1 - 0.5 + (posX - x) / 50;
+ const dx = Math.random() * 1 - 0.5 + (posX - x - len / 2) / 30
const dy = Math.random() * -0.7 - 1.4;
- const clearParticle = { x: posX, y: posY, colour, size: this.size, life, dx, dy, xF: 0.96, yF: 0.96, gravity: 0.05 }
- const particle = new Point(clearParticle, this.ctx);
- this.particles.push(particle);
+ const clearParticle = { x: posX, y: posY, colour, life, dx, dy, xF: 0.96, yF: 0.96, gravity: 0.05 }
+ new Point(clearParticle, this);
}
}
@@ -109,12 +118,11 @@ export class Particles {
const posX = x + Math.random() * len
const posY = y + Math.random() * height;
const life = Math.random() * 20 + 40;
- const dx = Math.random() * 1.5 - 0.75 + (posX - x) / 200;
+ const dx = Math.random() * 1.5 - 0.75 + (posX - x - len / 2) / 150;
const dy = Math.random() * -0.8 - 1.5;
- const clearParticle = { x: posX, y: posY, colour, size: this.size, life, dx, dy, yF: 0.99, gravity: 0.1 }
- const particle = new Point(clearParticle, this.ctx);
- this.particles.push(particle);
+ const clearParticle = { x: posX, y: posY, colour, life, dx, dy, yF: 0.99, gravity: 0.1 }
+ new Point(clearParticle, this);
}
}
@@ -127,9 +135,8 @@ export class Particles {
const dy = Math.random() * -8 - 2;
const colour = `hsl(${Math.random() * 360}, 80%, 60%)`
- const pcParticle = { x: posX, y: posY, colour, size: this.size, life, dx, dy, xF: 0.98, yF: 0.98, twinkle: true, twinkleTime: 130 }
- const particle = new Point(pcParticle, this.ctx);
- this.particles.push(particle);
+ const pcParticle = { x: posX, y: posY, colour, life, dx, dy, xF: 0.98, yF: 0.98, twinkle: true, twinkleTime: 130 }
+ new Point(pcParticle, this);
}
}
@@ -143,9 +150,8 @@ export class Particles {
const dy = Math.random() * -1.2 - 2.4;
const sway = Math.random() * 0.005 - 0.0025;
- const dangerParticle = { x: posX, y: posY, colour, size: this.size, life, dx, dy, sway, swayF: 0.98 }
- const particle = new Point(dangerParticle, this.ctx);
- this.particles.push(particle);
+ const dangerParticle = { x: posX, y: posY, colour, life, dx, dy, sway, swayF: 0.98 }
+ new Point(dangerParticle, this);
}
}
@@ -160,26 +166,24 @@ export class Particles {
const dx = (direction ? 1 : -1) * (Math.random() * 2 + 2);
const dy = Math.random() * 2 - 1;
- const dangerSideParticle = { x: posX, y: posY, colour, size: this.size, life, dx, dy, gravity: 0.05 }
- const particle = new Point(dangerSideParticle, this.ctx);
- this.particles.push(particle);
+ const dangerSideParticle = { x: posX, y: posY, colour, life, dx, dy, gravity: 0.05 }
+ new Point(dangerSideParticle, this);
}
}
createSpinParticles(x, y, colour, cw, len, height) {
len *= 0.5;
height *= 0.5;
- for (let i = 0; i < this.volume / 3; i++) {
- const posX = x + Math.random() * len - len / 2
- const posY = y + Math.random() * height - height / 2;
+ for (let i = 0; i < this.volume / 5; i++) {
+ const posX = x + Math.random() * len
+ const posY = y + Math.random() * height
const life = Math.random() * 35 + 70;
- let dx = Math.random() * 1 - 0.5 + (posY - y) / 30;
- let dy = Math.random() * 1 - 0.5 + (posX - x) / 30;
+ let dx = Math.random() * 1 - 0.5 + (posY - y) / 50;
+ let dy = Math.random() * 1 - 0.5 + (posX - x) / 50;
if (cw) { dx *= -1 } else { dy *= -1 }
- const spinParticle = { x: posX, y: posY, colour, size: this.size, life, dx, dy, xF: 0.98, yF: 0.98 }
- const particle = new Point(spinParticle, this.ctx);
- this.particles.push(particle);
+ const spinParticle = { x: posX, y: posY, colour, life, dx, dy, xF: 0.98, yF: 0.98 }
+ new Point(spinParticle, this);
}
}
@@ -191,9 +195,8 @@ export class Particles {
const dx = Math.random() * 1 - 0.5;
const dy = Math.random() * 1 - 0.5;
- const spikeParticle = { x: posX, y: posY, colour, size: this.size, life, dx, dy, xF: 0.96, yF: 0.96, twinkle: true }
- const particle = new Point(spikeParticle, this.ctx);
- this.particles.push(particle);
+ const spikeParticle = { x: posX, y: posY, colour, life, dx, dy, xF: 0.96, yF: 0.96, twinkle: true }
+ new Point(spikeParticle, this);
}
}
@@ -207,17 +210,25 @@ export class Particles {
const dx = (direction ? 1 : -1) * (Math.random() * 2);
const dy = Math.random() * 2 - 1;
- const BTBParticle = { x: posX, y: posY, colour, size: this.size, life, dx, dy, gravity: 0.15 }
- const particle = new Point(BTBParticle, this.ctx);
- this.particles.push(particle);
+ const BTBParticle = { x: posX, y: posY, colour, life, dx, dy, gravity: 0.15 }
+ new Point(BTBParticle, this);
}
}
- clearParticles() {
- this.particles = [];
+ clearParticles() { // there was a memory leak... so i fixed it
+ if (this.container == undefined) return;
+ const c = [...this.container.children]
+ c.forEach(child => { child.destroy(); this.container.removeChild(child); });
+ this.particles = new Array();
}
update() {
+ this.particles.forEach(particle => {
+ if (particle.life <= 0) { // something here worked to fix memory leak
+ this.container.removeChild(particle.particle);
+ // particle.particle.destroy();
+ }
+ })
this.particles = this.particles.filter(p => p.life > 0);
this.particles.forEach(particle => {
particle.update();
diff --git a/src/display/pixirender.js b/src/display/pixirender.js
new file mode 100644
index 0000000..941191f
--- /dev/null
+++ b/src/display/pixirender.js
@@ -0,0 +1,380 @@
+import { Game } from '../game.js';
+import { defaultSkins } from '../data/data.js';
+import blocksprites from '../data/blocksprites.json' with { type: 'json' };
+
+export class PixiRender {
+ textures = {};
+ minoSize;
+ width;
+ height;
+ resetAnimLength = 30;
+ resetAnimCurrent = 30;
+ boardAlpha = 1;
+ queueAlpha = 1;
+ justPlacedCoords = [];
+ justPlacedAlpha = 1;
+ flashTimes = [];
+
+ divlock = document.getElementById("lockTimer");
+
+ /**
+ * @param {Game} game
+ */
+ constructor(game) {
+ this.game = game;
+ }
+
+ async init() {
+ this.app = new PIXI.Application();
+ await this.app.init({ backgroundAlpha: 0, resizeTo: window });
+ document.body.appendChild(this.app.canvas);
+
+ // grid
+ const grid = new PIXI.Container();
+ this.app.stage.addChild(grid);
+ grid.label = "grid";
+
+ // board
+ this.board = new PIXI.Container();
+ this.app.stage.addChild(this.board);
+ this.board.label = "board";
+
+ const next = new PIXI.Container();
+ this.app.stage.addChild(next);
+ next.label = "next";
+
+ const hold = new PIXI.Container();
+ this.app.stage.addChild(hold);
+ hold.label = "hold";
+
+ // particles
+ const particles = new PIXI.Container();
+ this.app.stage.addChild(particles);
+ particles.label = "particles";
+ this.game.particles.initBoard();
+
+ // init
+ this.generateTextures();
+ this.game.particles.loadTexture();
+ this.resize();
+ this.generateAllSprites("board", this.game.board.boardState, 39, [0, 0]);
+ this.generateAllSprites("hold", this.game.renderer.holdQueueGrid, 2, [0, 0]);
+ this.generateAllSprites("next", this.game.renderer.nextQueueGrid, 15, [0, 0]);
+
+ this.app.ticker.add(time => this.tick(time));
+ }
+
+ resize() {
+ const grid = this.app.stage.getChildByLabel("grid");
+ const next = this.app.stage.getChildByLabel("next");
+ const hold = this.app.stage.getChildByLabel("hold");
+ const board = this.app.stage.getChildByLabel("board");
+ const particles = this.app.stage.getChildByLabel("particles");
+
+ // clear
+ grid.children.forEach(child => child.destroy());
+ grid.removeChildren();
+
+ // resize
+ const scale = Number(this.game.settings.display.boardHeight) / 100;
+ let height = this.app.screen.height * 0.6 * scale; // equivilant to 60vh
+ let width = height / 2;
+ const screenHeight = Math.floor(this.app.screen.height / 2);
+ const screenWidth = Math.floor(this.app.screen.width / 2);
+ this.minoSize = height / 20;
+ this.width = width;
+ this.height = height;
+
+ // board
+ const rect = new PIXI.Graphics().rect(0, 0, width, height * 2)
+ board.addChild(rect);
+ board.x = screenWidth;
+ board.y = screenHeight;
+ board.pivot.x = width / 2;
+ board.pivot.y = height * 3 / 2;
+
+ // hold
+ hold.x = screenWidth;
+ hold.y = screenHeight;
+ hold.pivot.x = width / 2 + width * 2 / 5;
+ hold.pivot.y = height / 2;
+
+ // next
+ next.x = screenWidth;
+ next.y = screenHeight;
+ next.pivot.x = width / 2 - width;
+ next.pivot.y = height / 2;
+
+ // grid and outline
+ const rectGrid = new PIXI.Graphics()
+ .rect(0, 0, width, height)
+ .stroke({ color: 0xffffff, width: 1, alignment: 0.5 })
+ grid.addChild(rectGrid);
+
+ const rectHold = new PIXI.Graphics()
+ .rect(0, 0, width * 2 / 5, height * 3 / 20)
+ .stroke({ color: 0xffffff, width: 1 })
+ grid.addChild(rectHold);
+ rectHold.x = - width * 2 / 5;
+
+ const rectNext = new PIXI.Graphics()
+ .rect(0, 0, width * 2 / 5, height * 16 / 20)
+ .stroke({ color: 0xffffff, width: 1 })
+ grid.addChild(rectNext);
+ rectNext.x = width;
+
+ grid.x = screenWidth;
+ grid.y = screenHeight;
+ grid.pivot.x = width / 2;
+ grid.pivot.y = height / 2;
+
+ // particles
+ particles.x = screenWidth;
+ particles.y = screenHeight;
+ particles.pivot.x = width / 2;
+ particles.pivot.y = height * 3 / 2;
+
+ this.generateGrid();
+ }
+
+ // GENRATORS
+ async generateTextures() {
+ let url = this.game.settings.display.skin;
+ if (defaultSkins.includes(url)) url = `./assets/skins/${url}.png`;
+ const texture = await PIXI.Assets.load(url);
+ const spritesheet = new PIXI.Spritesheet(texture, blocksprites);
+ await spritesheet.parse();
+ this.textures = spritesheet.textures;
+ this.game.renderer.updateNext();
+ this.game.renderer.updateHold();
+
+ const triangleGraphic = new PIXI.Graphics().poly([0, 0, 10, 0, 0, 10]).fill(0xffffff, 0.4);
+ this.triangle = this.app.renderer.generateTexture(triangleGraphic);
+
+ const triangleGraphic2 = new PIXI.Graphics().poly([0, 0, 100, 0, 0, 100]).fill(0xffffff);
+ triangleGraphic2.rotation = Math.PI * 3 / 2
+ triangleGraphic2.y = this.height * 2
+ triangleGraphic2.label = "invincible"
+ this.resetTriangle = triangleGraphic2;
+
+ const maskTriangle = new PIXI.Graphics().poly([-this.height, 0, this.width, 0, this.width, this.height + this.width]).fill(0xffffff, 0.4);
+ maskTriangle.x = this.width;
+ maskTriangle.y = this.height;
+ maskTriangle.pivot.x = this.width;
+ maskTriangle.label = "invincible";
+ this.resetMask = maskTriangle;
+ }
+
+ generateAllSprites(type, array, yPosChange, [dx, dy] = [0, 0]) {
+ const container = this.app.stage.getChildByLabel(type);
+
+ array.forEach((row, y) => {
+ row.forEach((col, x) => {
+ const posX = x * this.minoSize;
+ const posY = (yPosChange - y) * this.minoSize;
+ const sprite = new PIXI.Sprite(this.textures['g']);
+ sprite.x = (posX + dx);
+ sprite.y = (posY + dy);
+ sprite.width = this.minoSize;
+ sprite.height = this.minoSize;
+ sprite.visible = false;
+ sprite.label = `invincible ${x}${y}`;
+ container.addChild(sprite);
+ });
+ });
+ }
+
+ generateGrid() {
+ if (this.game.settings.display.showGrid === false) return;
+ const grid = this.app.stage.getChildByLabel("grid");
+ const type = this.game.settings.display.gridType;
+ const opacity = this.game.settings.display.gridopacity / 100;
+ const gridGraphic = new PIXI.Graphics();
+
+ if (type == "square") {
+ gridGraphic.rect(0, 0, this.minoSize, this.minoSize)
+ .stroke({ color: 0xffffff, width: 1, alpha: opacity })
+ } else if (type == "round") {
+ gridGraphic.roundRect(0, 0, this.minoSize, this.minoSize, 8)
+ .stroke({ color: 0xffffff, width: 1, alpha: opacity })
+ } else if (type == "dot") {
+ gridGraphic.circle(2, 2, 1)
+ .fill(0xffffff, opacity)
+ }
+ const texture = this.app.renderer.generateTexture(gridGraphic);
+
+ for (let y = 0; y < 20; y++) {
+ for (let x = 0; x < 10; x++) {
+ const gridSquare = new PIXI.Sprite(texture);
+ gridSquare.x = x * this.minoSize;
+ gridSquare.y = y * this.minoSize;
+ grid.addChild(gridSquare);
+ }
+ }
+ }
+
+ // RENDER CLOCK
+ tick(time) {
+ this.render("board", this.game.board.boardState);
+ this.game.boardeffects.move(0, 0);
+ this.game.boardeffects.rotate(0);
+ this.game.particles.update();
+ this.game.renderer.dangerParticles();
+ this.game.pixi.resetAnimation();
+ this.updateAlpha();
+ if (this.game.settings.game.gamemode == "ultra" && Math.floor(this.game.stats.time) == 60) this.game.renderer.renderTimeLeft("60S LEFT");
+ if (this.game.settings.game.gamemode == "ultra" && Math.floor(this.game.stats.time) == 90) this.game.renderer.renderTimeLeft("30S LEFT");
+ }
+
+ // RENDERING
+ render(type, array) {
+ if (this.app === undefined) return;
+
+ /** @type {PIXI.Container} */
+ const container = this.app.stage.getChildByLabel(type);
+ const c = [...container.children];
+ c.forEach(child => {
+ if (child.label.split(" ")[0] == "invincible") return;
+ child.destroy(); // fixed a memory leak (-2 hours)
+ container.removeChild(child);
+ });
+
+ array.forEach((row, y) => {
+ row.forEach((col, x) => {
+ const cell = col.split(" ");
+ let sprite = container.getChildByLabel(`invincible ${x}${y}`);
+ sprite.visible = false;
+ if (cell.includes("A") || cell.includes("S")) { // active or stopped piece
+ sprite.visible = true;
+ sprite.texture = this.textures[this.getPiece(type, cell[1].toLowerCase())];
+ sprite.alpha = this.getOpacity(cell, type, x, y) ?? this.queueAlpha;
+ } else if (cell.includes("NP") && this.game.renderer.inDanger) { // next piece overlay
+ sprite.visible = true;
+ sprite.texture = this.textures["topout"];
+ sprite.alpha = 0.32;
+ } else if (cell.includes("Sh")) { // shadow piece
+ const pieceName = this.game.settings.display.colouredShadow ? this.game.falling.piece.name : "shadow";
+ sprite.visible = true;
+ sprite.texture = this.textures[pieceName];
+ sprite.alpha = this.getShadowOpacity();
+ }
+ });
+ });
+
+ if (type == "board") this.updateMinoFlash(container);
+ }
+
+ updateMinoFlash(cont) {
+ this.flashTimes = this.flashTimes
+ .filter(({ c, t }) => t > 0)
+ .map(({ c, t }) => { return { c, t: t - 1 }; });
+
+ for (let { c, t } of this.flashTimes) {
+ const [x, y] = c;
+ const progress = (t / 15) * this.minoSize;
+ const triangle = new PIXI.Sprite(this.triangle);
+ triangle.x = x * this.minoSize;
+ triangle.y = (39 - y) * this.minoSize;
+ triangle.width = progress;
+ triangle.height = progress;
+
+ cont.addChild(triangle);
+ }
+ }
+
+ getPiece(type, cell) {
+ return this.game.hold.occured && type == "hold" ? "hold" : cell;
+ }
+
+ getOpacity(cell, type, x, y) {
+ if (type != "board") return;
+ if (this.divlock.value != 0 && cell.includes("A") && this.game.settings.game.gamemode != "lookahead") {
+ return 1 - (this.divlock.value / 250);
+ }
+ if (this.game.settings.game.gamemode == "lookahead") {
+ for (let [posX, posY] of this.justPlacedCoords) {
+ if (posX == x && posY == y) {
+ return Math.max(this.justPlacedAlpha, this.boardAlpha).toFixed(2);
+ }
+ }
+ }
+
+ return this.boardAlpha.toFixed(2);
+ }
+
+ getShadowOpacity() {
+ const opacity = this.game.settings.display.shadowOpacity / 100;
+ if (this.game.settings.game.gamemode == "lookahead") return (opacity * this.boardAlpha).toFixed(2);
+ return opacity;
+ }
+
+ removeCoords([x, y]) {
+ this.justPlacedCoords = this.justPlacedCoords.filter(c => !(c[0] == x && c[1] == y));
+ this.flashTimes = this.flashTimes.filter(({ c, t }) => !(c[0] == x && c[1] == y));
+ }
+
+ updateAlpha() {
+ if (this.game.settings.game.gamemode != 'lookahead') return;
+ const update = (type, amount) => {
+ if (this.game.stats.checkInvis()) {
+ if (this[type] <= 0) {
+ this[type] = 1;
+ this.game.renderer.updateNext();
+ this.game.renderer.updateHold();
+ }
+ } else {
+ if (this[type] > 0) {
+ this[type] += -amount / this.game.tickrate;
+ this.game.renderer.updateNext();
+ this.game.renderer.updateHold();
+ } else {
+ this[type] = 0;
+ }
+ }
+ }
+ update("boardAlpha", 3)
+ update("queueAlpha", 3)
+ update("justPlacedAlpha", 6)
+ }
+
+ // RESET ANIMATION
+ startResetAnimation() {
+ this.board.mask = this.resetMask;
+ this.board.addChild(this.resetMask);
+ this.board.addChild(this.resetTriangle);
+ this.game.stopGameTimers();
+ this.game.controls.resetting = true;
+ this.resetAnimCurrent = 0;
+ }
+
+ resetAnimation() {
+ if (this.resetAnimCurrent >= this.resetAnimLength * 2) return;
+ this.resetAnimCurrent++; // fade after animation
+ if (this.boardAlpha < 0.99) this.boardAlpha += 2 / this.resetAnimLength;
+ if (this.resetAnimCurrent > this.resetAnimLength) return;
+
+ // animation using mask
+ const progress = this.easeInOutCubic(this.resetAnimCurrent / this.resetAnimLength);
+ this.resetMask.scale.set(1 - progress, 1 - progress);
+ this.resetTriangle.scale.set(progress * 9, progress * 9);
+
+ this.board.mask = this.resetMask;
+
+ if (this.resetAnimCurrent == this.resetAnimLength) this.endResetAnimation();
+ }
+
+ endResetAnimation() {
+ this.game.startGame();
+ this.game.controls.resetting = false;
+ this.boardAlpha = 0;
+ setTimeout(() => {
+ this.board.removeChild(this.resetMask);
+ this.board.mask = null;
+ this.board.removeChild(this.resetTriangle);
+ }, 0)
+ }
+
+ easeInOutCubic(x) {
+ return -(Math.cos(Math.PI * x) - 1) / 2;
+ }
+}
diff --git a/src/display/renderBoard.js b/src/display/renderBoard.js
deleted file mode 100644
index 5853757..0000000
--- a/src/display/renderBoard.js
+++ /dev/null
@@ -1,160 +0,0 @@
-import { Game } from "../game.js";
-
-export class BoardRenderer {
- boardAlpha = 1;
- queueAlpha = 1;
- justPlacedCoords = [];
- justPlacedAlpha = 1;
- minoSize;
- texture;
- flashTimes = [];
-
- divlock = document.getElementById("lockTimer");
-
- /**
- *
- * @param {Game} game
- */
- constructor(game) {
- this.game = game;
- }
-
- // board rendering
- getOpacity(cell, cntx, x, y) {
- if (cntx != this.game.renderer.ctx) return;
- if (this.divlock.value != 0 && cell.includes("A") && this.game.settings.game.gamemode != "lookahead") {
- return 1 - (this.divlock.value / 250);
- }
- if (this.game.settings.game.gamemode == "lookahead") {
- for (let [posX, posY] of this.justPlacedCoords) {
- if (posX == x && posY == y && cntx == this.game.renderer.ctx) {
- return Math.max(this.justPlacedAlpha, this.boardAlpha).toFixed(2);
- }
- }
- }
-
- return this.boardAlpha.toFixed(2);
- }
-
- setMinoFlash(cntx, x, y, posX, posY) {
- if (cntx != this.game.renderer.ctx) return;
- for (let { c, t } of this.flashTimes) {
- if (c[0] == x && c[1] == y) {
- const dx = (t / 15) * this.minoSize;
- posX = posX + this.minoSize;
- posY = posY + this.minoSize;
- this.drawTriangle(posX, posY, posX - dx, posY - dx, cntx);
- }
- }
- }
-
- drawTriangle(posX, posY, x, y, cntx) {
- cntx.globalAlpha = 0.4;
- cntx.fillStyle = "#ffffff"
- cntx.beginPath();
- cntx.moveTo(posX, posY);
- cntx.lineTo(posX, y);
- cntx.lineTo(x, posY);
- cntx.lineTo(posX, posY);
- cntx.fill();
- }
-
- toHex(num) {
- const hex = Math.round((+num * 255) / 100).toString(16);
- return hex.length > 1 ? hex : 0 + hex;
- }
-
- loadImage(src) {
- this.texture = new Image(372, 30);
- this.texture.src = src;
- this.texture.onload = () => {
- this.game.renderer.updateNext();
- }
- }
-
- getPiece(cntx, cell) {
- return this.game.hold.occured && cntx == this.game.renderer.ctxH ? "hold" : cell;
- }
-
- getTexture(name) {
- const pieces = ["z", "l", "o", "s", "i", "j", "t", "shadow", "hold", "g", "darkg", "topout"]
- const x = pieces.indexOf(name.toLowerCase()) * 31;
- const y = 0;
- const width = 30;
- const height = 30;
- return { x, y, width, height };
- }
-
- getShadowOpacity() {
- const opacity = this.game.settings.display.shadowOpacity / 100;
- if (this.game.settings.game.gamemode == "lookahead") return (opacity * this.boardAlpha).toFixed(2);
- return opacity;
- }
-
- removeCoords([x, y]) {
- this.justPlacedCoords = this.justPlacedCoords.filter(c => !(c[0] == x && c[1] == y));
- this.flashTimes = this.flashTimes.filter(({ c, t }) => !(c[0] == x && c[1] == y));
- }
-
- renderBorder(ctx, x, y) {
- const type = this.game.settings.display.gridType;
- if (type == "round") {
- ctx.beginPath();
- ctx.roundRect(x, y, this.minoSize - 1, this.minoSize - 1, this.minoSize / 4);
- ctx.stroke();
- } else if (type == "square") {
- ctx.beginPath();
- ctx.strokeRect(x, y, this.minoSize - 1, this.minoSize - 1, this.minoSize / 4);
- ctx.stroke();
- } else if (type == "dot") {
- ctx.beginPath();
- ctx.arc(x + this.minoSize, y + this.minoSize, 1, 0, 2 * Math.PI);
- ctx.stroke();
- ctx.beginPath();
- ctx.arc(x, y, 1, 0, 2 * Math.PI);
- ctx.stroke();
- }
- }
-
- /**
- * @param {CanvasRenderingContext2D} cntx
- */
- renderToCanvas(cntx, grid, yPosChange, [dx, dy] = [0, 0], width, height) {
- cntx.clearRect(0, 0, width, height);
- grid.forEach((row, y) => {
- row.forEach((col, x) => {
- const [posX, posY] = [x * this.minoSize, (yPosChange - y) * this.minoSize];
- const cell = col.split(" ");
- cntx.lineWidth = 1;
-
- if (cell.includes("A") || cell.includes("S")) { // active piece or stopped piece
- cntx.globalAlpha = this.getOpacity(cell, cntx, x, y) ?? this.queueAlpha.toFixed(2);
- const p = this.getTexture(this.getPiece(cntx, cell[1]));
- cntx.drawImage(this.texture, p.x, p.y, p.width, p.height, posX + dx, posY + dy, this.minoSize, this.minoSize);
- this.setMinoFlash(cntx, x, y, posX + dx, posY + dy);
- }
- else if (cell.includes("NP") && this.game.renderer.inDanger) { // next piece overlay
- cntx.globalAlpha = 0.32;
- const p = this.getTexture("topout");
- cntx.drawImage(this.texture, p.x, p.y, p.width, p.height, posX + dx, posY + dy, this.minoSize, this.minoSize);
- }
- else if (cell.includes("Sh")) { // shadow piece
- cntx.globalAlpha = this.getShadowOpacity();
- const piece = this.game.settings.display.colouredShadow ? this.game.falling.piece.name : "shadow";
- const p = this.getTexture(piece);
- cntx.drawImage(this.texture, p.x, p.y, p.width, p.height, posX + dx, posY + dy, this.minoSize, this.minoSize);
- }
- else if (y < 20 && this.game.settings.display.showGrid && cntx == this.game.renderer.ctx) { // grid
- cntx.globalAlpha = 1
- cntx.strokeStyle = "#ffffff" + this.toHex(this.game.settings.display.gridopacity);
- this.renderBorder(cntx, posX, posY);
- }
- });
- });
-
- // flash
- this.flashTimes = this.flashTimes
- .filter(({ c, t }) => t > 0)
- .map(({ c, t }) => { return { c, t: t - 1 }; });
- }
-}
\ No newline at end of file
diff --git a/src/display/renderer.js b/src/display/renderer.js
index d761704..80fa81b 100644
--- a/src/display/renderer.js
+++ b/src/display/renderer.js
@@ -1,32 +1,17 @@
import { Game } from "../game.js";
import pieces from "../data/pieces.json" with { type: "json" };
-import { defaultSkins, statDecimals, statsSecondary as statsSecondaries } from "../data/data.js";
+import { statDecimals, statsSecondary as statsSecondaries } from "../data/data.js";
export class Renderer {
- boardHeight;
- boardWidth;
- holdHeight;
- holdWidth;
- nextHeight;
- nextWidth;
holdQueueGrid = [];
nextQueueGrid = [];
inDanger;
texttimeouts = {};
- resetAnimLength = 30;
- resetAnimCurrent = 30;
-
+
sidebarStats;
sidebarFixed;
sidebarSecondary;
- /** @type {CanvasRenderingContext2D} */
- ctx;
- ctxN;
- ctxH;
-
- canvasField = document.getElementById("playingfield");
- canvasNext = document.getElementById("next");
- canvasHold = document.getElementById("hold");
+
divBoard = document.getElementById("board");
divBackboard = document.getElementById("backboard");
divLinesSent = document.getElementById("linessent");
@@ -48,39 +33,6 @@ export class Renderer {
constructor(game) {
this.game = game;
this.board = game.board;
-
- this.ctx = this.canvasField.getContext("2d");
- this.ctxN = this.canvasNext.getContext("2d");
- this.ctxH = this.canvasHold.getContext("2d");
- }
-
- renderingLoop() {
- this.game.boardrender.renderToCanvas(this.ctx, this.game.board.boardState, 39, [0, 0], this.boardWidth, this.boardHeight);
- this.game.boardeffects.move(0, 0);
- this.game.boardeffects.rotate(0);
- this.game.particles.update();
- this.dangerParticles();
- this.resetAnimation();
- requestAnimationFrame(this.renderingLoop.bind(this))
- if(this.game.settings.game.gamemode == "ultra" && Math.floor(this.game.stats.time) == 60) this.renderTimeLeft("60S LEFT")
- if(this.game.settings.game.gamemode == "ultra" && Math.floor(this.game.stats.time) == 90) this.renderTimeLeft("30S LEFT")
- }
-
- sizeCanvas() {
- this.renderStyles();
- [this.canvasField, this.canvasNext, this.canvasHold].forEach(c => {
- c.width = Math.round(c.offsetWidth / 10) * 10;
- c.height = Math.round(c.offsetHeight / 40) * 40;
- });
- this.divBoard.style.width = `${this.canvasField.width}px`;
- this.divBoard.style.height = `${this.canvasField.height / 2}px`;
- this.game.boardrender.minoSize = this.canvasField.width / 10;
- this.boardWidth = this.canvasField.offsetWidth;
- this.boardHeight = this.canvasField.offsetHeight;
- this.nextWidth = this.canvasNext.offsetWidth;
- this.nextHeight = this.canvasNext.offsetHeight;
- this.holdWidth = this.canvasHold.offsetWidth;
- this.holdHeight = this.canvasHold.offsetHeight;
}
updateNext() {
@@ -95,9 +47,9 @@ export class Renderer {
coords.forEach(([x, y]) => (this.nextQueueGrid[y + dy][x + dx] = "A " + piece.name));
});
- this.game.boardrender.renderToCanvas(this.ctxN, this.nextQueueGrid, 15, [0, 0], this.nextWidth, this.nextHeight);
- if (this.game.settings.game.gamemode == 'lookahead' || !this.game.settings.display.colouredQueues) return;
- this.canvasNext.style.outlineColor = this.game.bag.nextPiece().colour;
+ this.game.pixi.render("next", this.nextQueueGrid);
+ // if (this.game.settings.game.gamemode == 'lookahead' || !this.game.settings.display.colouredQueues) return;
+ // this.canvasNext.style.outlineColor = this.game.bag.nextPiece().colour;
}
getPiece(name) {
@@ -117,17 +69,17 @@ export class Renderer {
const coords = this.board.pieceToCoords(this.game.hold.piece.shape1);
coords.forEach(([x, y]) => (this.holdQueueGrid[y + dy][x + dx] = "A " + name));
- const len = Math.round(this.game.boardrender.minoSize / 2);
+ const len = Math.round(this.game.pixi.minoSize / 2);
const [shiftX, shiftY] = [isO || isI ? 0 : len, isI ? 0 : len];
- this.game.boardrender.renderToCanvas(this.ctxH, this.holdQueueGrid, 2, [shiftX, shiftY], this.holdWidth, this.holdHeight);
- if (this.game.settings.game.gamemode == 'lookahead' || !this.game.settings.display.colouredQueues) return;
- const colour = this.game.hold.occured ? "gray" : this.game.hold.piece.colour
- this.canvasHold.style.outline = `0.2vh solid ${colour}`;
+ this.game.pixi.render("hold", this.holdQueueGrid);
+ // if (this.game.settings.game.gamemode == 'lookahead' || !this.game.settings.display.colouredQueues) return;
+ // const colour = this.game.hold.occured ? "gray" : this.game.hold.piece.colour
+ // this.canvasHold.style.outline = `0.2vh solid ${colour}`;
}
clearHold() {
- this.ctxH.clearRect(0, 0, this.canvasHold.offsetWidth + 10, this.canvasHold.offsetHeight);
+ this.game.pixi.render("hold", this.holdQueueGrid);
}
renderDanger() {
@@ -203,27 +155,22 @@ export class Renderer {
this.texttimeouts[name] = 0;
}
- renderStyles() {
+ renderStyles(settings = false) {
// custom background
const bg = this.game.settings.display.background;
if (bg == "") bg = "#080B0C";
document.body.style.background = (bg[0] == "#") ? bg : `url("${bg}") no-repeat center center`
document.body.style.backgroundSize = "cover";
- const height = Number(this.game.settings.display.boardHeight) + 10;
+ const height = Number(this.game.settings.display.boardHeight);
this.divBoard.style.transform = `scale(${height}%) translate(-50%, -50%)`;
- this.canvasHold.style.outline = `0.2vh solid #dbeaf3`;
+ // this.canvasHold.style.outline = `0.2vh solid #dbeaf3`;
// board opacity
const background = `rgba(0, 0, 0, ${Number(this.game.settings.display.boardOpacity) / 100})`;
this.divBackboard.style.backgroundColor = background;
document.body.style.setProperty('--background', background);
- // skins
- let skin = this.game.settings.display.skin;
- if (defaultSkins.includes(skin)) skin = `./assets/skins/${skin}.png`;
- this.game.boardrender.loadImage(skin);
-
// sidebar constants
this.sidebarStats = this.game.settings.game.sidebar;
this.sidebarFixed = this.sidebarStats.map(stat => this.createReverseLookup(statDecimals)[stat]);
@@ -233,6 +180,8 @@ export class Renderer {
if (stat == "None") stat = ""
this[`elementStatname${index + 1}`].textContent = stat;
})
+
+ if (settings) this.game.pixi.resize();
}
renderSidebar() {
@@ -241,6 +190,7 @@ export class Renderer {
this[`elementStats${index + 1}`].textContent = "";
return;
};
+
const displayStat = this.game.stats[stat].toFixed(this.sidebarFixed[index]);
this[`elementStats${index + 1}`].textContent = displayStat;
@@ -274,31 +224,6 @@ export class Renderer {
return reverseLookup
}
- updateAlpha() {
- if (this.game.settings.game.gamemode != 'lookahead') return;
- const update = (type, amount) => {
- if (this.game.stats.checkInvis()) {
- if (this.game.boardrender[type] <= 0) {
- this.game.boardrender[type] = 1;
- this.updateNext();
- this.updateHold();
- }
- } else {
- if (this.game.boardrender[type] > 0) {
- this.game.boardrender[type] += -amount / this.game.tickrate;
- this.updateNext();
- this.updateHold();
- } else {
- this.game.boardrender[type] = 0;
- }
- }
- }
- update("boardAlpha", 3)
- update("queueAlpha", 3)
- update("justPlacedAlpha", 6)
-
- }
-
setEditPieceColours() {
const elPieces = [...this.elementEditPieces.children];
elPieces.forEach(elpiece => {
@@ -325,45 +250,4 @@ export class Renderer {
this.game.particles.spawnParticles(0, 20, "dangersides");
}
- resetAnimation() {
- if (this.resetAnimCurrent >= this.resetAnimLength * 2) return;
- this.resetAnimCurrent++;
- if (this.game.boardrender.boardAlpha < 0.99) this.game.boardrender.boardAlpha += 2 / this.resetAnimLength;
- if (this.resetAnimCurrent > this.resetAnimLength) return;
-
-
- const progress = this.resetAnimCurrent / this.resetAnimLength;
- const startY = this.boardHeight / 2;
- const dx = this.boardWidth;
- const dy = dx + this.boardHeight / 2;
-
- const fillTriangle = (p, colour) => {
- this.ctx.globalAlpha = 1;
- this.ctx.fillStyle = colour;
- this.ctx.beginPath();
- this.ctx.moveTo(0, startY - dy * p);
- this.ctx.lineTo(dy * p, startY);
- this.ctx.lineTo(0, startY + dy * p);
- this.ctx.lineTo(0, 0);
- this.ctx.fill();
- }
- // fill triangle
- const progress1 = this.easeInOutCubic(progress);
- fillTriangle(progress1, 'white');
-
- // clear smaller triangle
- const progress2 = this.easeInOutCubic(progress - 0.1);
- fillTriangle(progress2, 'black');
-
-
- if (this.resetAnimCurrent == this.resetAnimLength) { // finished
- this.game.startGame();
- this.game.controls.resetting = false;
- this.game.boardrender.boardAlpha = 0;
- }
- }
-
- easeInOutCubic(x) {
- return -(Math.cos(Math.PI * x) - 1) / 2;
- }
}
diff --git a/src/features/sounds.js b/src/features/sounds.js
index 2a1d360..a29eb51 100644
--- a/src/features/sounds.js
+++ b/src/features/sounds.js
@@ -93,7 +93,7 @@ export class Sounds {
const name = file.name.split(".")[0];
const a = new Audio(file.path);
this.sfx[name] = a;
- this.playSound(name, false, true);
+ // this.playSound(name, false, true);
})
@@ -111,7 +111,7 @@ export class Sounds {
track.connect(this.lowpassfilter);
this.lowpassfilter.connect(this.audioContext.destination);
})
- // this.playSound("allclear") // wait literally how is this fine by chrome
+ // this.playSound("allclear") // i knew it was a bad idea
}
setAudioLevel() {
diff --git a/src/game.js b/src/game.js
index 5da791e..ed53cd8 100644
--- a/src/game.js
+++ b/src/game.js
@@ -16,9 +16,9 @@ import { History } from "./features/history.js";
import { BoardEffects } from "./display/boardEffects.js";
import { ProfileStats } from "./features/profileStats.js";
import { Modes } from "./features/modes.js";
-import { BoardRenderer } from "./display/renderBoard.js";
import { Particles } from "./display/particles.js";
import { Zenith } from "./mechanics/zenith.js";
+import { PixiRender } from "./display/pixirender.js";
export class Game {
started;
@@ -26,7 +26,7 @@ export class Game {
gameTimer = 0; // id of timeout
survivalTimer = 0; // id of timeout
gravityTimer = 0;
- version = '1.3.2';
+ version = '1.3.4';
tickrate = 60;
elementReason = document.getElementById("reason");
@@ -49,20 +49,19 @@ export class Game {
this.modals = new ModalActions(this);
this.movement = new Movement(this);
this.renderer = new Renderer(this);
- this.boardrender = new BoardRenderer(this);
this.particles = new Particles(this);
this.boardeditor = new BoardEditor(this);
this.controls = new Controls(this);
this.history = new History(this);
this.modes = new Modes(this);
- this.zenith = new Zenith(this)
+ this.zenith = new Zenith(this);
+ this.pixi = new PixiRender(this);
- this.renderer.sizeCanvas();
- this.particles.initBoard();
+ this.renderer.renderStyles();
this.renderer.setEditPieceColours();
this.sounds.initSounds();
this.startGame();
- this.renderer.renderingLoop();
+ this.pixi.init();
this.boardeditor.addListeners();
this.menuactions.addRangeListener();
this.modals.generate.addMenuListeners();
@@ -117,8 +116,8 @@ export class Game {
resetState() {
this.boardeffects.hasPace = true;
this.boardeffects.paceCooldown = 0;
- this.boardrender.boardAlpha = 1;
- this.boardrender.queueAlpha = 1;
+ this.pixi.boardAlpha = 1;
+ this.pixi.queueAlpha = 1;
this.renderer.inDanger = false;
this.started = false;
this.ended = false;
@@ -143,7 +142,7 @@ export class Game {
this.renderer.renderSidebar();
this.modes.checkFinished();
this.stats.updateStats();
- this.renderer.updateAlpha();
+ this.pixi.updateAlpha();
this.boardeffects.rainbowBoard();
}
@@ -151,7 +150,6 @@ export class Game {
this.renderer.renderSidebar();
this.modes.checkFinished();
this.stats.updateStats();
- this.renderer.updateAlpha();
this.boardeffects.rainbowBoard();
}
diff --git a/src/main.js b/src/main.js
index d36e77d..cbb8b81 100644
--- a/src/main.js
+++ b/src/main.js
@@ -31,11 +31,13 @@ window.addEventListener('mousemove', () => {
game.controls.toggleCursor(true);
})
-document.onresize = () => {
- game.renderer.sizeCanvas();
- game.renderer.updateNext();
- game.renderer.updateHold();
-}
+window.addEventListener("resize", () => {
+ setTimeout(() => {
+ game.pixi.resize();
+ game.renderer.updateNext();
+ game.renderer.updateHold();
+ }, 0);
+})
// splash menu
window.addEventListener("DOMContentLoaded", () => {
@@ -56,5 +58,11 @@ window.addEventListener("blur", function () {
});
window.onerror = (msg, url, lineNo, columnNo, error) => {
- game.modals.generate.notif(error, msg + ". ln "+ lineNo, "error");
-}
\ No newline at end of file
+ game.modals.generate.notif(error, msg + ". ln " + lineNo, "error");
+}
+
+document.getElementById("playingfield").style.display = 'none'
+document.getElementById("next").style.display = 'none'
+document.getElementById("hold").style.display = 'none'
+document.getElementById("backboard").style.display = 'none'
+document.getElementById("backborder").style.display = 'none'
\ No newline at end of file
diff --git a/src/mechanics/board.js b/src/mechanics/board.js
index cf1532d..33426ad 100644
--- a/src/mechanics/board.js
+++ b/src/mechanics/board.js
@@ -103,11 +103,14 @@ export class Board {
setComboBoard(start) {
// 4w sides
- this.boardState.forEach((row, y) =>
+
+ const board = JSON.parse(JSON.stringify(this.boardState));
+ board.forEach((row, y) => {
row.forEach((col, x) => {
- if (x < 3 || x > 6) this.addMinos("S G", [[x, y]], [0, 0]);
+ if ((x > 2 && x < 7) || y > 30) return;
+ this.setValue([x, y], 'S G')
})
- );
+ })
if (!start) return;
// garbage pattern
@@ -123,5 +126,6 @@ export class Board {
this.addMinos("S G", garbCoords.map(([x, y]) => [x + 3, y]), [0, 0]);
this.game.mechanics.setShadow();
+
}
}
diff --git a/src/mechanics/clearlines.js b/src/mechanics/clearlines.js
index 3964865..2380dd6 100644
--- a/src/mechanics/clearlines.js
+++ b/src/mechanics/clearlines.js
@@ -24,7 +24,7 @@ export class ClearLines {
removedGarbage++;
stopped.filter(c => c[1] == row).forEach(([x, y]) => { // clear rows
this.game.mechanics.board.setCoordEmpty([x, y]);
- this.game.boardrender.removeCoords([x, y]);
+ this.game.pixi.removeCoords([x, y]);
});
this.game.mechanics.board.moveMinos(stopped.filter(c => c[1] > row), "DOWN", 1);
}
diff --git a/src/mechanics/locking.js b/src/mechanics/locking.js
index 1300be0..9d01734 100644
--- a/src/mechanics/locking.js
+++ b/src/mechanics/locking.js
@@ -71,11 +71,11 @@ export class LockPiece {
lockPiece() {
const lockCoords = this.game.mechanics.board.getMinos("A");
- this.game.boardrender.justPlacedCoords = lockCoords;
- this.game.boardrender.justPlacedAlpha = 1;
+ this.game.pixi.justPlacedCoords = lockCoords;
+ this.game.pixi.justPlacedAlpha = 1;
lockCoords.forEach(([x, y]) => {
- this.game.boardrender.flashTimes.push({ c: [x, y], t: 15 })
+ this.game.pixi.flashTimes.push({ c: [x, y], t: 15 })
this.game.mechanics.board.rmValue([x, y], "A");
this.game.mechanics.board.addValFront([x, y], "S");
});
@@ -106,7 +106,7 @@ export class LockPiece {
const xvals = [...new Set(lockCoords.map(([x, y]) => x))];
const yval = Math.min(...lockCoords.map(([x, y]) => y));
- this.game.particles.spawnParticles(Math.min(...xvals) + 1, yval, "lock", xvals.length);
+ this.game.particles.spawnParticles(Math.min(...xvals), yval, "lock", xvals.length);
this.game.renderer.renderDanger();
const delay = (cleared > 0) ? this.game.settings.game.clearDelay : 0;
diff --git a/src/menus/modals.js b/src/menus/modals.js
index a3f1f1b..53a323b 100644
--- a/src/menus/modals.js
+++ b/src/menus/modals.js
@@ -97,7 +97,7 @@ export class ModalActions {
if (id != 'changeRangeValue' && id != "frontdrop" && this.game.started && !this.game.ended)
this.game.movement.firstMovement();
this.actions.saveSettings();
- if (id == "displayDialog") this.game.renderer.renderStyles();
+ if (id == "displayDialog") this.game.renderer.renderStyles(true);
const restartMenus = ["gameDialog", "gamemodeDialog", "gameEnd", "goalsDialog", "competitiveDialog"];
if (restartMenus.includes(id)) this.game.controls.retry(false);
diff --git a/src/movement/controls.js b/src/movement/controls.js
index fc44288..f9f3637 100644
--- a/src/movement/controls.js
+++ b/src/movement/controls.js
@@ -9,6 +9,7 @@ export class Controls {
timings = { arr: 0, das: 0, sd: 0 }; // timeout and interval ids
menuKey = "Escape"; // html modals close using escape
cursorVisible = true;
+ resetting = false;
/**
* @param {Game} game
@@ -145,8 +146,6 @@ export class Controls {
this.timings[name] = 0;
}
- resetting = false;
-
retry(animation) {
if (this.resetting) return; // no overlap
this.game.ended = true;
@@ -157,9 +156,7 @@ export class Controls {
return;
}
- this.game.stopGameTimers()
- this.resetting = true;
- this.game.renderer.resetAnimCurrent = 0; // start animation
+ this.game.pixi.startResetAnimation()
}
toggleCursor(enable) {
diff --git a/src/movement/movement.js b/src/movement/movement.js
index a43fe55..7387db0 100644
--- a/src/movement/movement.js
+++ b/src/movement/movement.js
@@ -93,7 +93,7 @@ export class Movement {
this.game.controls.checkSD();
if (this.game.mechanics.isTspin || (this.game.mechanics.isAllspin && this.game.settings.game.allspin)) {
this.game.renderer.rotateBoard(type);
- this.game.particles.spawnParticles(this.game.falling.location[0], this.game.falling.location[1] + 2,
+ this.game.particles.spawnParticles(...this.game.falling.location,
"spin", 5, type == "CW", this.game.falling.piece.colour);
this.game.sounds.playSound("spin");
}
@@ -155,7 +155,7 @@ export class Movement {
this.game.sounds.playSound("harddrop");
this.game.renderer.bounceBoard('DOWN');
const xvals = [...new Set(minos.map(([x, y]) => x))];
- this.game.particles.spawnParticles(Math.min(...xvals)+1, this.game.falling.location[1], "drop", xvals.length);
+ this.game.particles.spawnParticles(Math.min(...xvals), this.game.falling.location[1], "drop", xvals.length);
this.game.mechanics.locking.lockPiece();
}
}
diff --git a/styles/style.css b/styles/style.css
index b3b09af..72980c8 100644
--- a/styles/style.css
+++ b/styles/style.css
@@ -20,8 +20,8 @@ body {
color: var(--cl-blue);
font-family: "Major Mono Display", monospace;
margin: 0;
- height: 100vh;
- width: 100vw;
+ /* height: 100vh; */
+ /* width: 100vw; */
overflow: hidden;
background: var(--night);
--background: black;
From 82e797b4e7fb0bf05ce3669c8693049e8efc712f Mon Sep 17 00:00:00 2001
From: TitanPlayz <118145727+TitanPlayz100@users.noreply.github.com>
Date: Sun, 27 Oct 2024 23:04:13 +1100
Subject: [PATCH 3/6] most of the board is using new style now, still some
todos remaining
---
assets/icons/play.svg | 1 +
assets/icons/reset.svg | 2 +-
index.html | 49 +----
info.md | 41 +++-
src/data/defaultSettings.json | 1 -
src/display/boardEffects.js | 11 +-
src/display/particles.js | 9 +-
src/display/pixirender.js | 389 ++++++++++++++++++++++++++--------
src/display/renderer.js | 113 +++-------
src/features/editboard.js | 8 +-
src/features/modes.js | 9 +-
src/game.js | 12 +-
src/main.js | 16 +-
src/mechanics/clearlines.js | 1 -
src/mechanics/locking.js | 2 +-
src/mechanics/zenith.js | 5 +-
src/menus/menuactions.js | 6 +-
src/movement/controls.js | 5 +-
styles/boards.css | 76 +------
styles/menus.css | 37 +---
styles/settings.css | 1 -
styles/style.css | 40 ----
22 files changed, 424 insertions(+), 410 deletions(-)
create mode 100644 assets/icons/play.svg
diff --git a/assets/icons/play.svg b/assets/icons/play.svg
new file mode 100644
index 0000000..5422941
--- /dev/null
+++ b/assets/icons/play.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/icons/reset.svg b/assets/icons/reset.svg
index 1556771..0b47741 100644
--- a/assets/icons/reset.svg
+++ b/assets/icons/reset.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/index.html b/index.html
index b8fbb1a..584ed06 100644
--- a/index.html
+++ b/index.html
@@ -10,58 +10,25 @@
-
+
+
+
-
⚠ GO DOWN
-
-
-
-
-
-
-
-
-
-
-
-
-
60S LEFT
-
+
-
-
-
Next
-
Hold
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
history: 0
-
-
+
history: 0
+
1
2
@@ -79,6 +46,9 @@
Teti
+
+
+
@@ -154,7 +124,6 @@ Teti
-
diff --git a/info.md b/info.md
index 18e2262..4811fcc 100644
--- a/info.md
+++ b/info.md
@@ -69,18 +69,53 @@ Skins from [YHF](https://you.have.fail/ed/at/tetrioplus/)
Things that I am working on based on other changes
- ready set go start option
- arcade mode
-- cooler action text
+
+Zenith mode additions
+- add fatigue:
+8:00 - 2 permanent garbage
+9:00 - receive 25% more garbage
+10:00 - 3 more permanent garbage (5 total)
+11:00 - debuff increased to 50% more garbage
+12:00 - 5 more permanent garbage (10 total)
+
+- maybe add a "currently in hyperspeed" graphic
+- simulated garbage recieving option
+ - amount of garbage sent to player increases with floor
+ - garbage is random bursts
+ - attacks 8 or larger split using {!!} thing (0.5s gap)
+- option for expert mode style
+
+- update climb bar colours:
+Red (#e43921)
+Yellow (#ffb400)
+Green (#82fc40)
+Blue (#3ca6ff)
+Magenta (#ff46da)
+Khaki (#ffc48e)
+"Teal Green" (#99ffc6)
+"Cyan Blue" (#00f7ff)
+"Soft Pink" (#ffbbea)
+White (#ffffff)
+
***
## Updates
-#### v1.3.4 => PIXIjs
+#### v1.3.5
+- New board design inspired from [this reddit post](https://www.reddit.com/r/Tetris/comments/1g80adg/tetris_ui_concept/)
+- added continue button in menu, and changed ingame buttons to use pixijs now
+- experimenting with animation library called gsap
+- changed action text and stats text to use pixi now
+- changed PC text to be more TETR.IO-like
+- changed spike text to show in the middle of the board (like techmino)
+- RIP coloured queues
+
+#### v1.3.4 => PIXI.js
- COMPLETE REWRITE OF ALL GRAPHICS
- Everything is now rendered through pixijs
- this includes the board, next queue, hold queue, and particles
- ye turns out there is a high learning curve with pixi (i lost it several times)
- everything should now be much more performant and smooth yay
-
- some things were changed due to this
- need to add border colour back
diff --git a/src/data/defaultSettings.json b/src/data/defaultSettings.json
index 5b69262..13b626f 100644
--- a/src/data/defaultSettings.json
+++ b/src/data/defaultSettings.json
@@ -8,7 +8,6 @@
"shadowOpacity": 20,
"boardHeight": 80,
"colouredShadow": false,
- "colouredQueues": true,
"lockBar": true,
"rainbowPB": true,
"boardBounce": 2,
diff --git a/src/display/boardEffects.js b/src/display/boardEffects.js
index 4298107..7d82384 100644
--- a/src/display/boardEffects.js
+++ b/src/display/boardEffects.js
@@ -18,9 +18,8 @@ export class BoardEffects {
paceCooldown = 0;
divBoard = document.getElementById("board");
- divDanger = document.getElementById("dangerOverlay");
- border = document.getElementById('backborder')
- backboard = document.getElementById('backboard')
+ // border = document.getElementById('backborder')
+ // backboard = document.getElementById('backboard')
/**
*
@@ -101,14 +100,10 @@ export class BoardEffects {
}
toggleRainbow(pace) {
+ return;
this.border.style.setProperty('--blur-size', pace ? `0.3vmin` : `0vmin`)
this.border.style.setProperty('--blur-strength', pace ? '0.7vmin' : '0')
this.backboard.style.setProperty('--blur-strength', pace ? '0.5vmin' : '0')
this.hasPace = pace;
}
-
- toggleDangerBoard(inDanger) {
- this.border.classList.toggle("boardDanger", inDanger);
- this.divDanger.style.opacity = inDanger ? "0.1" : "0";
- }
}
\ No newline at end of file
diff --git a/src/display/particles.js b/src/display/particles.js
index ca5dace..b7253f4 100644
--- a/src/display/particles.js
+++ b/src/display/particles.js
@@ -20,10 +20,9 @@ class Point {
this.twinkle = twinkle ?? false;
this.twinkleTime = twinkleTime ?? this.life;
- const particle = new PIXI.Sprite(particleInstance.texture);
- this.particle = particle;
+ this.particle = particleInstance.game.pixi.createParticleSprite()
this.particle.tint = colour;
- particleInstance.container.addChild(particle);
+ particleInstance.container.addChild(this.particle);
particleInstance.particles.push(this);
}
@@ -62,10 +61,6 @@ export class Particles {
this.container = this.game.pixi.app.stage.getChildByLabel("particles");
}
- async loadTexture() {
- this.texture = await PIXI.Assets.load('./assets/particle.png');
- }
-
spawnParticles(posX, posY, type, pieceWidth = 1, cw = false, colour = "white") {
if (!this.game.settings.display.particles) return;
diff --git a/src/display/pixirender.js b/src/display/pixirender.js
index 941191f..20e3b77 100644
--- a/src/display/pixirender.js
+++ b/src/display/pixirender.js
@@ -1,19 +1,19 @@
import { Game } from '../game.js';
import { defaultSkins } from '../data/data.js';
import blocksprites from '../data/blocksprites.json' with { type: 'json' };
+import { clearSplash } from '../main.js';
export class PixiRender {
textures = {};
minoSize;
width;
height;
- resetAnimLength = 30;
- resetAnimCurrent = 30;
boardAlpha = 1;
queueAlpha = 1;
justPlacedCoords = [];
justPlacedAlpha = 1;
- flashTimes = [];
+ shadowSprites = {};
+ editButtonVisible = false;
divlock = document.getElementById("lockTimer");
@@ -26,7 +26,7 @@ export class PixiRender {
async init() {
this.app = new PIXI.Application();
- await this.app.init({ backgroundAlpha: 0, resizeTo: window });
+ await this.app.init({ backgroundAlpha: 0, resizeTo: window, autoDensity: true });
document.body.appendChild(this.app.canvas);
// grid
@@ -47,6 +47,10 @@ export class PixiRender {
this.app.stage.addChild(hold);
hold.label = "hold";
+ const textContainer = new PIXI.Container();
+ this.app.stage.addChild(textContainer);
+ textContainer.label = "textContainer";
+
// particles
const particles = new PIXI.Container();
this.app.stage.addChild(particles);
@@ -54,14 +58,18 @@ export class PixiRender {
this.game.particles.initBoard();
// init
- this.generateTextures();
- this.game.particles.loadTexture();
+ await this.generateTextures();
this.resize();
this.generateAllSprites("board", this.game.board.boardState, 39, [0, 0]);
this.generateAllSprites("hold", this.game.renderer.holdQueueGrid, 2, [0, 0]);
this.generateAllSprites("next", this.game.renderer.nextQueueGrid, 15, [0, 0]);
+ this.game.renderer.updateNext();
+ this.game.renderer.updateHold();
this.app.ticker.add(time => this.tick(time));
+
+ gsap.registerPlugin(PixiPlugin);
+ PixiPlugin.registerPIXI(PIXI);
}
resize() {
@@ -70,10 +78,12 @@ export class PixiRender {
const hold = this.app.stage.getChildByLabel("hold");
const board = this.app.stage.getChildByLabel("board");
const particles = this.app.stage.getChildByLabel("particles");
+ const textContainer = this.app.stage.getChildByLabel("textContainer");
// clear
grid.children.forEach(child => child.destroy());
grid.removeChildren();
+ textContainer.removeChildren();
// resize
const scale = Number(this.game.settings.display.boardHeight) / 100;
@@ -94,34 +104,62 @@ export class PixiRender {
board.pivot.y = height * 3 / 2;
// hold
+ const clickRectHold = new PIXI.Graphics().rect(0, 0, width * 2 / 5, height * 3 / 20).fill("transparent");
+ clickRectHold.interactive = true;
+ clickRectHold.cursor = 'pointer'
+ clickRectHold.on("pointerdown", () => this.game.modals.openModal("queueModify"));
+ clickRectHold.label = "invincible"
+ hold.addChild(clickRectHold);
hold.x = screenWidth;
- hold.y = screenHeight;
+ hold.y = screenHeight + height * 2 / 20;
hold.pivot.x = width / 2 + width * 2 / 5;
hold.pivot.y = height / 2;
// next
+ const clickRectNext = new PIXI.Graphics().rect(0, 0, width * 2 / 5, height * 16 / 20).fill("transparent");
+ clickRectNext.interactive = true;
+ clickRectNext.cursor = 'pointer'
+ clickRectNext.on("pointerdown", () => this.game.modals.openModal("queueModify"));
+ clickRectNext.label = "invincible"
+ next.addChild(clickRectNext);
next.x = screenWidth;
- next.y = screenHeight;
- next.pivot.x = width / 2 - width;
+ next.y = screenHeight + height * 1 / 20;
+ next.pivot.x = width / 2 - width * 11 / 10;
next.pivot.y = height / 2;
// grid and outline
- const rectGrid = new PIXI.Graphics()
+ const { textHold, textNext } = this.textGraphics(width);
+ const { settings, reset, edit } = this.buttonGraphics(width);
+
+ this.boardBG = new PIXI.Graphics()
.rect(0, 0, width, height)
- .stroke({ color: 0xffffff, width: 1, alignment: 0.5 })
- grid.addChild(rectGrid);
+ .fill("red")
+ this.boardBG.alpha = 0;
+ grid.addChild(this.boardBG);
+
+ this.border = new PIXI.Graphics()
+ .lineTo(0, height).lineTo(width, height).lineTo(width, 0)
+ .stroke({ color: 0xffffff, width: 2, alignment: 0.5 })
+ grid.addChild(this.border);
const rectHold = new PIXI.Graphics()
- .rect(0, 0, width * 2 / 5, height * 3 / 20)
+ .moveTo(0, height * 1 / 4).lineTo(width * 2 / 5, height * 1 / 4)
.stroke({ color: 0xffffff, width: 1 })
grid.addChild(rectHold);
rectHold.x = - width * 2 / 5;
+ grid.addChild(textHold);
const rectNext = new PIXI.Graphics()
- .rect(0, 0, width * 2 / 5, height * 16 / 20)
+ .moveTo(0, height * 17 / 20).lineTo(width * 2 / 5, height * 17 / 20)
.stroke({ color: 0xffffff, width: 1 })
grid.addChild(rectNext);
rectNext.x = width;
+ grid.addChild(textNext);
+
+ grid.addChild(settings);
+ grid.addChild(reset);
+ grid.addChild(edit);
+ this.editButton = edit;
grid.x = screenWidth;
grid.y = screenHeight;
@@ -134,29 +172,194 @@ export class PixiRender {
particles.pivot.x = width / 2;
particles.pivot.y = height * 3 / 2;
+ // action text
+ textContainer.x = screenWidth;
+ textContainer.y = screenHeight;
+ textContainer.pivot.x = width / 2;
+ textContainer.pivot.y = height / 2;
+
+ textContainer.addChild(this.actionTexts.cleartext.sprite)
+ textContainer.addChild(this.actionTexts.combotext.sprite)
+ textContainer.addChild(this.actionTexts.btbtext.sprite)
+ textContainer.addChild(this.actionTexts.spiketext.sprite)
+ textContainer.addChild(this.actionTexts.pctext.sprite)
+ this.statTexts.forEach((text) => {
+ textContainer.addChild(text.stat);
+ textContainer.addChild(text.statText);
+ textContainer.addChild(text.statSecondary);
+ });
+ textContainer.addChild(this.objectiveTexts[0])
+ textContainer.addChild(this.objectiveTexts[1])
+
this.generateGrid();
+ this.resetAnimGraphic();
}
- // GENRATORS
- async generateTextures() {
- let url = this.game.settings.display.skin;
- if (defaultSkins.includes(url)) url = `./assets/skins/${url}.png`;
- const texture = await PIXI.Assets.load(url);
- const spritesheet = new PIXI.Spritesheet(texture, blocksprites);
- await spritesheet.parse();
- this.textures = spritesheet.textures;
- this.game.renderer.updateNext();
- this.game.renderer.updateHold();
+ // TEXT
+ textGraphics(width) {
+ const style = new PIXI.TextStyle({ fontFamily: "Major Mono Display", fontSize: 18, fill: 0xffffff, fontWeight: "bold", letterSpacing: 1 });
+
+ const textHold = new PIXI.Text({ text: "hold", style });
+ textHold.x = - width * 3.5 / 10;
+ textHold.resolution = 2;
+
+ const textNext = new PIXI.Text({ text: "next", style });
+ textNext.x = width * 11 / 10;
+ textNext.resolution = 2;
+
+ const actionStyle = new PIXI.TextStyle({ fontFamily: "Major Mono Display", fontSize: 24, fill: "white", fontWeight: "bold" });
+ const actionText = (pos) => {
+ const text = new PIXI.Text({ text: "", style: actionStyle });
+ text.resolution = 2;
+ text.alpha = 0;
+ text.y = pos * width * 1.5 / 10 + width * 3 / 5;
+ text.anchor.x = 1;
+ text.text = ""
+ return { sprite: text, animation: gsap.timeline() };
+ }
- const triangleGraphic = new PIXI.Graphics().poly([0, 0, 10, 0, 0, 10]).fill(0xffffff, 0.4);
- this.triangle = this.app.renderer.generateTexture(triangleGraphic);
+ const pcstyle = new PIXI.TextStyle({ fontFamily: "Major Mono Display", fontSize: 24, fill: "yellow", fontWeight: "bold", stroke: { color: "orange", width: 2 } });
+ const pcText = new PIXI.Text({ text: "perfect \n clear", style: pcstyle });
+ pcText.resolution = 2;
+ pcText.alpha = 0;
+ pcText.x = this.width / 2;
+ pcText.y = this.height / 2;
+ pcText.pivot.x = pcText.width / 2 - 10;
+ pcText.pivot.y = pcText.height / 2;
+
+ const spiketext = actionText(3);
+ spiketext.sprite.x = this.width / 2;
+ spiketext.sprite.y = this.height * 1 / 4;
+ spiketext.sprite.anchor.x = 0.5;
+ spiketext.sprite.anchor.y = 0.5;
+
+ this.actionTexts = {
+ cleartext: actionText(0),
+ combotext: actionText(1),
+ btbtext: actionText(2),
+ spiketext,
+ pctext: { sprite: pcText, animation: gsap.timeline() }
+ }
+
+ const statStyle = new PIXI.TextStyle({ fontFamily: "Major Mono Display", fontSize: 16, fill: "white", fontWeight: "bold" });
+ const statTextStyle = new PIXI.TextStyle({ fontFamily: "Montserrat", fontSize: 18, fill: "#999999" });
+ const statSecondaryStyle = new PIXI.TextStyle({ fontFamily: "Major Mono Display", fontSize: 26, fill: "white", fontWeight: "bold" });
+ const statText = (pos) => {
+ const stat = new PIXI.Text({ text: "", style: statStyle });
+ stat.resolution = 2;
+ stat.position.set(-width * 1 / 20, this.height - pos * this.height * 2.5 / 20)
+ stat.anchor.x = 1;
+ const statText = new PIXI.Text({ text: "", style: statTextStyle });
+ statText.resolution = 2;
+ statText.position.set(-width * 1 / 20, this.height - pos * this.height * 2.5 / 20 - this.height * 2 / 40)
+ statText.anchor.x = 1;
+ const statSecondary = new PIXI.Text({ text: "", style: statSecondaryStyle });
+ statSecondary.resolution = 2;
+ statSecondary.position.set(-width * 7 / 20, this.height - pos * this.height * 2.5 / 20 - this.height * 1 / 40)
+ statSecondary.anchor.x = 1;
+ return { stat, statText, statSecondary };
+ }
+
+ this.statTexts = [
+ statText(0.5),
+ statText(1.5),
+ statText(2.5)
+ ]
+
+ const objectiveText = new PIXI.Text({ text: "", style: statSecondaryStyle });
+ objectiveText.resolution = 2;
+ objectiveText.position.set(width*11/10, this.height - this.height * 3 / 40)
+
+ const objectiveNameText = new PIXI.Text({ text: "", style: statTextStyle });
+ objectiveNameText.resolution = 2;
+ objectiveNameText.position.set(width*11/10, this.height - this.height * 5/40)
+
+ this.objectiveTexts = [objectiveText, objectiveNameText];
+
+ return { textHold, textNext };
+ }
+
+ // todo reset action text
+ showActionText(type, message) {
+ this.actionTexts[type].animation.kill();
+ const text = this.actionTexts[type].sprite;
+ text.text = message;
+ this.actionTexts[type].animation = gsap.timeline({ onComplete: () => this.game.mechanics.spikeCounter = 0 })
+ .to(text, { duration: 0.2, pixi: { alpha: 1, x: - this.width * 1 / 10, scaleX: 1 }, ease: "power1.inOut" })
+ .to(text, { duration: 2, pixi: { alpha: 1, scaleX: 1.1 } })
+ .to(text, { duration: 0.2, pixi: { alpha: 0, x: 0 }, ease: "power1.inOut" })
+ }
+
+ showSpikeText(num) {
+ this.actionTexts.spiketext.animation.kill();
+ const { colour, power } = this.spikeTextStyle();
+ const text = this.actionTexts.spiketext.sprite;
+ text.text = num;
+ this.actionTexts.spiketext.animation = gsap.timeline()
+ .to(text, { duration: 0.1, pixi: { alpha: 0.8, tint: colour, scale: (1 + power / 8) } })
+ .to(text, { duration: (1 + power / 8) / power, pixi: { alpha: 0.2 }, ease: "power2.in", repeat: power - 1 })
+ .to(text, { duration: 0.2, pixi: { alpha: 0 }, ease: "power1.inOut" })
+ }
+
+ spikeTextStyle() {
+ if (this.game.mechanics.spikeCounter >= 20) return { colour: "#fad9f7", power: 12 };
+ if (this.game.mechanics.spikeCounter >= 15) return { colour: "#7ac9fa", power: 8 };
+ if (this.game.mechanics.spikeCounter >= 10) return { colour: "#faa823", power: 4 };
+ return { colour: "white", power: 1 };
+ }
+
+ showPCText() {
+ this.actionTexts.pctext.animation.kill();
+ const pc = this.actionTexts.pctext.sprite;
+ this.actionTexts.pctext.animation = gsap.timeline()
+ .to(pc, { duration: 0, pixi: { alpha: 1, scale: 0, rotation: -180 } })
+ .to(pc, { duration: 0.5, pixi: { scale: 1.6, rotation: 360 }, ease: "power1.inOut" })
+ .to(pc, { duration: 3.5 / 15, pixi: { tint: "orange" }, ease: "power1.inOut", repeat: 15, yoyo: true })
+ .to(pc, { duration: 2.5, pixi: { scale: 0, alpha: 0 }, ease: "power3.in" }, "1.5")
+ }
+
+ // GRAPHICS and GENERATORS
+ buttonGraphics(width) {
+ const iconframe = (texture, scale, y) => {
+ const icon = new PIXI.Sprite(texture)
+ icon.scale.set(scale)
+ icon.x = width * 1.525
+ icon.y = y
+ icon.interactive = true
+ icon.cursor = 'pointer'
+ icon.alpha = 0.6
+ icon.on("pointerover", () => gsap.to(icon, { duration: 0.1, pixi: { alpha: 1, scale: scale * 1.1 }, ease: "power1.inOut" }))
+ icon.on("pointerout", () => gsap.to(icon, { duration: 0.3, pixi: { alpha: 0.6, scale: scale }, ease: "power1.inOut" }))
+ return icon
+ }
+
+ const settings = iconframe(this.settingsIcon, 0.18, 0)
+ settings.on("pointerdown", () => this.game.modals.openModal("settingsPanel"));
+
+ const reset = iconframe(this.resetIcon, 0.23, width * 3 / 20)
+ reset.on("pointerdown", () => this.game.controls.retry(true));
+
+ const edit = iconframe(this.editIcon, 0.21, width * 6 / 20)
+ edit.on("pointerdown", () => this.game.modals.openModal("editMenu"));
+ edit.visible = this.editButtonVisible
+ return { settings, reset, edit };
+ }
+
+ toggleEditButton(bool) {
+ this.editButtonVisible = bool
+ this.editButton.visible = this.editButtonVisible;
+ }
+
+ resetAnimGraphic() {
+ if (this.resetTriangle) this.resetTriangle.destroy();
const triangleGraphic2 = new PIXI.Graphics().poly([0, 0, 100, 0, 0, 100]).fill(0xffffff);
triangleGraphic2.rotation = Math.PI * 3 / 2
triangleGraphic2.y = this.height * 2
triangleGraphic2.label = "invincible"
this.resetTriangle = triangleGraphic2;
+ if (this.resetMask) this.resetMask.destroy();
const maskTriangle = new PIXI.Graphics().poly([-this.height, 0, this.width, 0, this.width, this.height + this.width]).fill(0xffffff, 0.4);
maskTriangle.x = this.width;
maskTriangle.y = this.height;
@@ -165,25 +368,47 @@ export class PixiRender {
this.resetMask = maskTriangle;
}
+ async generateTextures() {
+ let url = this.game.settings.display.skin;
+ if (defaultSkins.includes(url)) url = `./assets/skins/${url}.png`;
+ const texture = await PIXI.Assets.load(url);
+ const spritesheet = new PIXI.Spritesheet(texture, blocksprites);
+ await spritesheet.parse();
+ this.textures = spritesheet.textures;
+
+ this.settingsIcon = await PIXI.Assets.load('./assets/icons/settings.svg');
+ this.resetIcon = await PIXI.Assets.load('./assets/icons/reset.svg');
+ this.editIcon = await PIXI.Assets.load('./assets/icons/edit.svg');
+
+ const triangleGraphic = new PIXI.Graphics().poly([0, 0, 10, 0, 0, 10]).fill(0xffffff, 0.4);
+ this.triangle = this.app.renderer.generateTexture(triangleGraphic);
+
+ this.game.particles.texture = await PIXI.Assets.load('./assets/particle.png');
+ clearSplash();
+ }
+
generateAllSprites(type, array, yPosChange, [dx, dy] = [0, 0]) {
const container = this.app.stage.getChildByLabel(type);
-
+ const shadowArray = [];
array.forEach((row, y) => {
+ const shadowRow = []
row.forEach((col, x) => {
const posX = x * this.minoSize;
const posY = (yPosChange - y) * this.minoSize;
const sprite = new PIXI.Sprite(this.textures['g']);
- sprite.x = (posX + dx);
- sprite.y = (posY + dy);
- sprite.width = this.minoSize;
- sprite.height = this.minoSize;
+ sprite.position.set(posX + dx, posY + dy);
+ sprite.setSize(this.minoSize);
sprite.visible = false;
- sprite.label = `invincible ${x}${y}`;
+ sprite.label = "invincible";
+ shadowRow.push(sprite);
container.addChild(sprite);
});
+ shadowArray.push(shadowRow);
});
+ this.shadowSprites[type] = shadowArray
}
+
generateGrid() {
if (this.game.settings.display.showGrid === false) return;
const grid = this.app.stage.getChildByLabel("grid");
@@ -220,7 +445,6 @@ export class PixiRender {
this.game.boardeffects.rotate(0);
this.game.particles.update();
this.game.renderer.dangerParticles();
- this.game.pixi.resetAnimation();
this.updateAlpha();
if (this.game.settings.game.gamemode == "ultra" && Math.floor(this.game.stats.time) == 60) this.game.renderer.renderTimeLeft("60S LEFT");
if (this.game.settings.game.gamemode == "ultra" && Math.floor(this.game.stats.time) == 90) this.game.renderer.renderTimeLeft("30S LEFT");
@@ -228,12 +452,10 @@ export class PixiRender {
// RENDERING
render(type, array) {
- if (this.app === undefined) return;
-
- /** @type {PIXI.Container} */
const container = this.app.stage.getChildByLabel(type);
- const c = [...container.children];
- c.forEach(child => {
+ const shadowArray = this.shadowSprites[type];
+
+ [...container.children].forEach(child => {
if (child.label.split(" ")[0] == "invincible") return;
child.destroy(); // fixed a memory leak (-2 hours)
container.removeChild(child);
@@ -242,11 +464,11 @@ export class PixiRender {
array.forEach((row, y) => {
row.forEach((col, x) => {
const cell = col.split(" ");
- let sprite = container.getChildByLabel(`invincible ${x}${y}`);
+ const sprite = shadowArray[y][x];
sprite.visible = false;
if (cell.includes("A") || cell.includes("S")) { // active or stopped piece
sprite.visible = true;
- sprite.texture = this.textures[this.getPiece(type, cell[1].toLowerCase())];
+ sprite.texture = this.getTexture(type, cell);
sprite.alpha = this.getOpacity(cell, type, x, y) ?? this.queueAlpha;
} else if (cell.includes("NP") && this.game.renderer.inDanger) { // next piece overlay
sprite.visible = true;
@@ -260,30 +482,25 @@ export class PixiRender {
}
});
});
-
- if (type == "board") this.updateMinoFlash(container);
}
- updateMinoFlash(cont) {
- this.flashTimes = this.flashTimes
- .filter(({ c, t }) => t > 0)
- .map(({ c, t }) => { return { c, t: t - 1 }; });
+ getTexture(type, cell) {
+ const piece = this.game.hold.occured && type == "hold" ? "hold" : cell[1].toLowerCase()
+ return this.textures[piece];
+ }
- for (let { c, t } of this.flashTimes) {
- const [x, y] = c;
- const progress = (t / 15) * this.minoSize;
+ // todo remove flash for cleared lines
+ flash(coords) {
+ coords.forEach(([x, y]) => {
const triangle = new PIXI.Sprite(this.triangle);
triangle.x = x * this.minoSize;
triangle.y = (39 - y) * this.minoSize;
- triangle.width = progress;
- triangle.height = progress;
-
- cont.addChild(triangle);
- }
- }
-
- getPiece(type, cell) {
- return this.game.hold.occured && type == "hold" ? "hold" : cell;
+ triangle.label = "invincible";
+ this.board.addChild(triangle);
+ gsap.timeline({ onComplete: () => this.board.removeChild(triangle) })
+ .to(triangle, { duration: 0, pixi: { width: this.minoSize, height: this.minoSize } })
+ .to(triangle, { duration: 0.15, pixi: { width: 0, height: 0 }, ease: "power1.inOut", })
+ })
}
getOpacity(cell, type, x, y) {
@@ -298,7 +515,6 @@ export class PixiRender {
}
}
}
-
return this.boardAlpha.toFixed(2);
}
@@ -308,11 +524,6 @@ export class PixiRender {
return opacity;
}
- removeCoords([x, y]) {
- this.justPlacedCoords = this.justPlacedCoords.filter(c => !(c[0] == x && c[1] == y));
- this.flashTimes = this.flashTimes.filter(({ c, t }) => !(c[0] == x && c[1] == y));
- }
-
updateAlpha() {
if (this.game.settings.game.gamemode != 'lookahead') return;
const update = (type, amount) => {
@@ -337,44 +548,42 @@ export class PixiRender {
update("justPlacedAlpha", 6)
}
- // RESET ANIMATION
- startResetAnimation() {
+ createParticleSprite() {
+ return new PIXI.Sprite(this.game.particles.texture);
+ }
+
+ toggleDangerBG(danger) {
+ gsap.to(this.boardBG, { duration: 0.2, pixi: { alpha: danger ? 0.1 : 0 } });
+ gsap.to(this.border, { duration: 0.2, pixi: { tint: danger ? "red" : "none" } });
+ }
+
+ resetAnimation() {
this.board.mask = this.resetMask;
this.board.addChild(this.resetMask);
this.board.addChild(this.resetTriangle);
this.game.stopGameTimers();
this.game.controls.resetting = true;
- this.resetAnimCurrent = 0;
- }
-
- resetAnimation() {
- if (this.resetAnimCurrent >= this.resetAnimLength * 2) return;
- this.resetAnimCurrent++; // fade after animation
- if (this.boardAlpha < 0.99) this.boardAlpha += 2 / this.resetAnimLength;
- if (this.resetAnimCurrent > this.resetAnimLength) return;
- // animation using mask
- const progress = this.easeInOutCubic(this.resetAnimCurrent / this.resetAnimLength);
- this.resetMask.scale.set(1 - progress, 1 - progress);
- this.resetTriangle.scale.set(progress * 9, progress * 9);
+ const animateOpacity = () => {
+ gsap.timeline()
+ .to(this.board, { duration: 0, pixi: { alpha: 0 } })
+ .to(this.board, { duration: 0.2, pixi: { alpha: 1 } })
+ }
- this.board.mask = this.resetMask;
+ gsap.timeline({ onComplete: () => { this.endResetAnimation(); animateOpacity(); } })
+ .to(this.resetMask, { duration: 0, pixi: { scale: 1 } })
+ .to(this.resetMask, { duration: 0.4, pixi: { scale: 0 }, ease: "power1.inOut", })
- if (this.resetAnimCurrent == this.resetAnimLength) this.endResetAnimation();
+ gsap.timeline()
+ .to(this.resetTriangle, { duration: 0, pixi: { scale: 0 } })
+ .to(this.resetTriangle, { duration: 0.4, pixi: { scale: 9 }, ease: "power1.inOut", })
}
endResetAnimation() {
this.game.startGame();
this.game.controls.resetting = false;
- this.boardAlpha = 0;
- setTimeout(() => {
- this.board.removeChild(this.resetMask);
- this.board.mask = null;
- this.board.removeChild(this.resetTriangle);
- }, 0)
- }
-
- easeInOutCubic(x) {
- return -(Math.cos(Math.PI * x) - 1) / 2;
+ this.board.mask = null;
+ this.board.removeChild(this.resetMask);
+ this.board.removeChild(this.resetTriangle);
}
}
diff --git a/src/display/renderer.js b/src/display/renderer.js
index 80fa81b..53c6610 100644
--- a/src/display/renderer.js
+++ b/src/display/renderer.js
@@ -13,26 +13,15 @@ export class Renderer {
sidebarSecondary;
divBoard = document.getElementById("board");
- divBackboard = document.getElementById("backboard");
- divLinesSent = document.getElementById("linessent");
elementEditPieces = document.getElementById("editMenuPieces");
-
- elementStats1 = document.getElementById("stats1");
- elementStats2 = document.getElementById("stats2");
- elementStats3 = document.getElementById("stats3");
- elementStatname1 = document.getElementById("statName1");
- elementStatname2 = document.getElementById("statName2");
- elementStatname3 = document.getElementById("statName3");
- elementSmallStat1 = document.getElementById("smallStat1");
- elementSmallStat2 = document.getElementById("smallStat2");
- elementSmallStat3 = document.getElementById("smallStat3");
-
/**
* @param {Game} game
*/
constructor(game) {
this.game = game;
this.board = game.board;
+ this.nextQueueGrid = [...Array(15)].map(() => [...Array(4)].map(() => ""));
+ this.holdQueueGrid = [...Array(3)].map(() => [...Array(4)].map(() => ""));
}
updateNext() {
@@ -48,8 +37,6 @@ export class Renderer {
});
this.game.pixi.render("next", this.nextQueueGrid);
- // if (this.game.settings.game.gamemode == 'lookahead' || !this.game.settings.display.colouredQueues) return;
- // this.canvasNext.style.outlineColor = this.game.bag.nextPiece().colour;
}
getPiece(name) {
@@ -67,15 +54,9 @@ export class Renderer {
isI = name == "i";
const [dx, dy] = [isO ? 1 : 0, isO ? 1 : isI ? -1 : 0];
const coords = this.board.pieceToCoords(this.game.hold.piece.shape1);
-
coords.forEach(([x, y]) => (this.holdQueueGrid[y + dy][x + dx] = "A " + name));
- const len = Math.round(this.game.pixi.minoSize / 2);
- const [shiftX, shiftY] = [isO || isI ? 0 : len, isI ? 0 : len];
this.game.pixi.render("hold", this.holdQueueGrid);
- // if (this.game.settings.game.gamemode == 'lookahead' || !this.game.settings.display.colouredQueues) return;
- // const colour = this.game.hold.occured ? "gray" : this.game.hold.piece.colour
- // this.canvasHold.style.outline = `0.2vh solid ${colour}`;
}
clearHold() {
@@ -89,22 +70,16 @@ export class Renderer {
if (condition && !this.inDanger) {
this.game.sounds.playSound("damage_alert");
}
- this.game.boardeffects.toggleDangerBoard(condition)
+ this.game.pixi.toggleDangerBG(condition);
this.inDanger = condition;
}
renderActionText(damagetype, isBTB, isPC, damage, linecount) {
- if (damagetype != "") this.setText("cleartext", damagetype, 2000);
- if (this.game.stats.combo > 0)
- this.setText("combotext", `Combo ${this.game.stats.combo}`, 2000);
- if (isBTB && this.game.stats.btbCount > 0)
- this.setText("btbtext", `BTB ${this.game.stats.btbCount} `, 2000);
- if (isPC) this.setText("pctext", "Perfect Clear", 2000);
- if (damage > 0) this.setText("linessent", `${this.game.mechanics.spikeCounter}`, 1500);
-
- if (this.game.mechanics.spikeCounter > 0) this.spikePattern("white", 1);
- if (this.game.mechanics.spikeCounter >= 10) this.spikePattern("red", 1.1);
- if (this.game.mechanics.spikeCounter >= 20) this.spikePattern("lime", 1.2);
+ if (damagetype != "") this.game.pixi.showActionText("cleartext", damagetype);
+ if (this.game.stats.combo > 0) this.game.pixi.showActionText("combotext", `Combo ${this.game.stats.combo}`);
+ if (isBTB && this.game.stats.btbCount > 0) this.game.pixi.showActionText("btbtext", `btb ${this.game.stats.btbCount} `);
+ if (this.game.mechanics.spikeCounter > 4) this.game.pixi.showSpikeText(`${this.game.mechanics.spikeCounter}`);
+ if (isPC) this.game.pixi.showPCText();
// audio
if (isPC) this.game.sounds.playSound("allclear");
@@ -125,31 +100,6 @@ export class Renderer {
this.game.sounds.playSound(`combo_${this.game.stats.combo > 16 ? 16 : this.game.stats.combo}`);
}
- resetActionText() {
- ['btbtext', 'cleartext', 'combotext', 'pctext', 'linessent'].forEach(id => {
- document.getElementById(id).style.opacity = "0";
- })
- }
-
- spikePattern(colour, size) {
- this.divLinesSent.style.color = colour;
- this.divLinesSent.style.textShadow = `0 0 1vh ${colour}`;
- this.divLinesSent.style.fontSize = `${3.5 * size}vh`;
- }
-
- setText(id, text, duration) {
- const textbox = document.getElementById(id);
- textbox.textContent = text;
- textbox.style.transform = "translateX(-2%)";
- textbox.style.opacity = "1";
- if (this.texttimeouts[id] != 0) this.stopTimeout(id);
- this.texttimeouts[id] = setTimeout(() => {
- textbox.style.opacity = "0";
- textbox.style.transform = "translateX(2%)";
- this.game.mechanics.spikeCounter = 0;
- }, duration);
- }
-
stopTimeout(name) {
clearTimeout(this.texttimeouts[name]);
this.texttimeouts[name] = 0;
@@ -164,12 +114,11 @@ export class Renderer {
const height = Number(this.game.settings.display.boardHeight);
this.divBoard.style.transform = `scale(${height}%) translate(-50%, -50%)`;
- // this.canvasHold.style.outline = `0.2vh solid #dbeaf3`;
// board opacity
- const background = `rgba(0, 0, 0, ${Number(this.game.settings.display.boardOpacity) / 100})`;
- this.divBackboard.style.backgroundColor = background;
- document.body.style.setProperty('--background', background);
+ // const background = `rgba(0, 0, 0, ${Number(this.game.settings.display.boardOpacity) / 100})`;
+ // this.divBackboard.style.backgroundColor = background;
+ // document.body.style.setProperty('--background', background);
// sidebar constants
this.sidebarStats = this.game.settings.game.sidebar;
@@ -178,7 +127,7 @@ export class Renderer {
this.sidebarStats.forEach((stat, index) => {
if (stat == "None") stat = ""
- this[`elementStatname${index + 1}`].textContent = stat;
+ this.game.pixi.statTexts[index].statText.text = stat.toUpperCase();
})
if (settings) this.game.pixi.resize();
@@ -187,20 +136,37 @@ export class Renderer {
renderSidebar() {
this.sidebarStats.forEach((stat, index) => {
if (stat == "None") { // no stat
- this[`elementStats${index + 1}`].textContent = "";
+ this.game.pixi.statTexts[index].stat.text = "";
return;
};
- const displayStat = this.game.stats[stat].toFixed(this.sidebarFixed[index]);
- this[`elementStats${index + 1}`].textContent = displayStat;
+ let displayStat = this.game.stats[stat].toFixed(this.sidebarFixed[index]) ?? "";
+ if (stat == "time") displayStat = this.formatTime(Number(displayStat), this.sidebarFixed[index]); // reformat time
+ this.game.pixi.statTexts[index].stat.text = displayStat;
if (this.sidebarSecondary[index]) {
- const displaySecond = this.game.stats[this.sidebarSecondary[index]]
- this[`elementSmallStat${index + 1}`].textContent = displaySecond;
+ const displaySecond = this.game.stats[this.sidebarSecondary[index]] ?? ""
+ this.game.pixi.statTexts[index].statSecondary.text = displaySecond;
}
})
}
+ createReverseLookup(obj) {
+ const reverseLookup = {}
+ for (const [key, array] of Object.entries(obj)) {
+ array.forEach(item => {
+ reverseLookup[item] = key;
+ });
+ }
+ return reverseLookup
+ }
+
+ formatTime(s, d) {
+ const minutes = Math.floor(s / 60);
+ const seconds = (s - minutes * 60).toFixed(d)
+ return `${minutes>0?minutes:""}:${seconds < 10 ? "0" : ""}${seconds}`
+ }
+
renderTimeLeft(text){
const e = document.getElementById("timeLeftText")
if (this.texttimeouts["timeLeft"] != 0){
@@ -214,16 +180,6 @@ export class Renderer {
}, 3000);
}
- createReverseLookup(obj) {
- const reverseLookup = {}
- for (const [key, array] of Object.entries(obj)) {
- array.forEach(item => {
- reverseLookup[item] = key;
- });
- }
- return reverseLookup
- }
-
setEditPieceColours() {
const elPieces = [...this.elementEditPieces.children];
elPieces.forEach(elpiece => {
@@ -249,5 +205,4 @@ export class Renderer {
this.game.particles.spawnParticles(0, 0, "dangerboard");
this.game.particles.spawnParticles(0, 20, "dangersides");
}
-
}
diff --git a/src/features/editboard.js b/src/features/editboard.js
index 194d45e..8a7878f 100644
--- a/src/features/editboard.js
+++ b/src/features/editboard.js
@@ -1,15 +1,13 @@
import { Game } from "../game.js";
export class BoardEditor {
- clickareasdiv = document.getElementById("clickareas");
+ // clickareasdiv = document.getElementById("clickareas");
mousedown = false;
currentMode = "fill";
fillPiece = 'G';
fillRow = false;
override = false;
- elementEditButton = document.getElementById("editButton");
-
/**
* @param {Game} game
*/
@@ -112,8 +110,4 @@ export class BoardEditor {
})
return { board, next, hold }
}
-
- setEditButton(bool) {
- this.elementEditButton.style.display = bool ? "flex" : "none";
- }
}
\ No newline at end of file
diff --git a/src/features/modes.js b/src/features/modes.js
index e89226a..5a9cdce 100644
--- a/src/features/modes.js
+++ b/src/features/modes.js
@@ -3,8 +3,6 @@ import gamemodeJSON from "../data/gamemodes.json" with { type: "json" };
import { gameoverResultText, gameoverText, resultSuffix } from "../data/data.js";
export class Modes {
- elementobjectives = document.getElementById("objective");
- divObjectiveText = document.getElementById("objectiveText");
modeJSON;
customSettings;
@@ -53,7 +51,7 @@ export class Modes {
if (statValue != undefined) statValue = Math.round(statValue * 1000) / 1000
let modetext = (statValue == undefined ? '' : statValue)
+ (resultValue == undefined ? '' : `/${resultValue}`)
- this.elementobjectives.textContent = modetext;
+ this.game.pixi.objectiveTexts[0].text = modetext;
}
loadModes() {
@@ -63,7 +61,10 @@ export class Modes {
currentGamemode = 'sprint'
}
this.setGamemode(currentGamemode);
- this.divObjectiveText.textContent = this.modeJSON.objectiveText;
+
+ this.game.pixi.objectiveTexts[1].text = this.modeJSON.objectiveText.toUpperCase();
+ this.game.history.setHistoryDiv(this.game.settings.game.gamemode == 'custom');
+ this.game.pixi.toggleEditButton(this.game.settings.game.gamemode == 'custom');
}
setGamemode(mode) {
diff --git a/src/game.js b/src/game.js
index ed53cd8..d1f7fb1 100644
--- a/src/game.js
+++ b/src/game.js
@@ -56,13 +56,19 @@ export class Game {
this.modes = new Modes(this);
this.zenith = new Zenith(this);
this.pixi = new PixiRender(this);
+ this.init();
+ }
+ async init() {
+ this.menuactions.loadSettings();
+ this.board.resetBoard();
+ await this.pixi.init();
+ this.modes.loadModes();
this.renderer.renderStyles();
this.renderer.setEditPieceColours();
this.sounds.initSounds();
this.startGame();
- this.pixi.init();
- this.boardeditor.addListeners();
+ // this.boardeditor.addListeners();
this.menuactions.addRangeListener();
this.modals.generate.addMenuListeners();
this.modals.generate.generateGamemodeMenu();
@@ -75,6 +81,7 @@ export class Game {
startGame() {
this.menuactions.loadSettings();
+ this.modes.loadModes();
this.resetState();
this.renderer.renderStyles();
this.mechanics.spawnPiece(this.bag.randomiser(true), true);
@@ -125,7 +132,6 @@ export class Game {
this.board.resetBoard();
this.mechanics.locking.clearLockDelay();
this.boardeffects.toggleRainbow(false);
- this.renderer.resetActionText();
this.renderer.renderDanger();
this.particles.clearParticles();
this.renderer.clearHold();
diff --git a/src/main.js b/src/main.js
index cbb8b81..c9c99c6 100644
--- a/src/main.js
+++ b/src/main.js
@@ -15,11 +15,12 @@ window.addEventListener("keydown", event => {
let key = event.key.length > 1 ? event.key : event.key.toLowerCase(); // 1 letter words are lowercase
if (event.altKey) key = "Alt+" + key;
if (event.ctrlKey) key = "Ctrl+" + key;
-
+
game.controls.onKeyDownRepeat(event, key);
if (event.repeat) return;
game.controls.onKeyDown(event, key);
-})
+});
+
window.addEventListener("keyup", event => {
if (event.key == undefined) return;
@@ -39,14 +40,13 @@ window.addEventListener("resize", () => {
}, 0);
})
-// splash menu
-window.addEventListener("DOMContentLoaded", () => {
+export function clearSplash() {
elementSplashText.textContent = "Ready";
elementSplashScreen.style.opacity = 0;
elementSplashScreen.style.scale = 1.2;
elementSplashScreen.style.display = "none";
document.getElementById("ignoreText").style.opacity = 0.5;
-})
+}
window.addEventListener("focus", function () {
document.getElementById("nofocus").style.display = "none";
@@ -60,9 +60,3 @@ window.addEventListener("blur", function () {
window.onerror = (msg, url, lineNo, columnNo, error) => {
game.modals.generate.notif(error, msg + ". ln " + lineNo, "error");
}
-
-document.getElementById("playingfield").style.display = 'none'
-document.getElementById("next").style.display = 'none'
-document.getElementById("hold").style.display = 'none'
-document.getElementById("backboard").style.display = 'none'
-document.getElementById("backborder").style.display = 'none'
\ No newline at end of file
diff --git a/src/mechanics/clearlines.js b/src/mechanics/clearlines.js
index 2380dd6..f342c87 100644
--- a/src/mechanics/clearlines.js
+++ b/src/mechanics/clearlines.js
@@ -24,7 +24,6 @@ export class ClearLines {
removedGarbage++;
stopped.filter(c => c[1] == row).forEach(([x, y]) => { // clear rows
this.game.mechanics.board.setCoordEmpty([x, y]);
- this.game.pixi.removeCoords([x, y]);
});
this.game.mechanics.board.moveMinos(stopped.filter(c => c[1] > row), "DOWN", 1);
}
diff --git a/src/mechanics/locking.js b/src/mechanics/locking.js
index 9d01734..596a776 100644
--- a/src/mechanics/locking.js
+++ b/src/mechanics/locking.js
@@ -75,10 +75,10 @@ export class LockPiece {
this.game.pixi.justPlacedAlpha = 1;
lockCoords.forEach(([x, y]) => {
- this.game.pixi.flashTimes.push({ c: [x, y], t: 15 })
this.game.mechanics.board.rmValue([x, y], "A");
this.game.mechanics.board.addValFront([x, y], "S");
});
+ this.game.pixi.flash(lockCoords);
this.game.mechanics.locking.clearLockDelay();
clearInterval(this.game.gravityTimer);
diff --git a/src/mechanics/zenith.js b/src/mechanics/zenith.js
index b4cb54f..98f213c 100644
--- a/src/mechanics/zenith.js
+++ b/src/mechanics/zenith.js
@@ -109,8 +109,9 @@ export class Zenith {
climbSpeedBar.value = point
climbSpeedBar.max = require
- document.styleSheets[1].cssRules[24].style.backgroundColor = color[speed - 1]
- document.styleSheets[1].cssRules[23].style.backgroundColor = color[speed]
+ // changes css variable, better selection
+ document.getElementById("climbSpeedBar").style.setProperty("--background-colour", color[speed-1])
+ document.getElementById("climbSpeedBar").style.setProperty("--bar-colour", color[speed])
}
}
\ No newline at end of file
diff --git a/src/menus/menuactions.js b/src/menus/menuactions.js
index 3120e4b..c92e70a 100644
--- a/src/menus/menuactions.js
+++ b/src/menus/menuactions.js
@@ -95,16 +95,11 @@ export class MenuActions {
loadSettings() {
const data = localStorage.getItem("settings") ?? "{}";
this.game.settings.load(JSON.parse(data))
- this.game.modes.loadModes();
- this.game.history.setHistoryDiv(this.game.settings.game.gamemode == 'custom');
- this.game.boardeditor.setEditButton(this.game.settings.game.gamemode == 'custom');
}
setGamemode(mode) {
this.game.modes.setGamemode(mode);
this.game.modes.loadModes();
- this.game.history.setHistoryDiv(this.game.settings.game.gamemode == 'custom');
- this.game.boardeditor.setEditButton(this.game.settings.game.gamemode == 'custom');
}
downloadSettings() {
@@ -124,6 +119,7 @@ export class MenuActions {
reader.onload = () => {
localStorage.setItem("settings", reader.result.toString());
this.loadSettings();
+ this.game.modes.loadModes();
this.game.modals.generate.notif("Settings Loaded", "User settings have successfully loaded", "message");
};
}
diff --git a/src/movement/controls.js b/src/movement/controls.js
index f9f3637..08734d0 100644
--- a/src/movement/controls.js
+++ b/src/movement/controls.js
@@ -153,10 +153,9 @@ export class Controls {
if (!animation || this.game.settings.game.stride) {
this.game.startGame();
- return;
+ } else {
+ this.game.pixi.resetAnimation()
}
-
- this.game.pixi.startResetAnimation()
}
toggleCursor(enable) {
diff --git a/styles/boards.css b/styles/boards.css
index e6f70ca..9c4dda7 100644
--- a/styles/boards.css
+++ b/styles/boards.css
@@ -7,7 +7,7 @@
height: 60vh;
aspect-ratio: 0.5;
}
-
+/*
#backboard,
#backborder {
position: absolute;
@@ -79,29 +79,7 @@
width: 100%;
height: 100%;
background-color: var(--background);
-}
-
-#backborder.boardDanger {
- outline: 0.2vh solid red !important;
- box-shadow: 0 0 3vh red !important;
- transition: all 0.5s ease;
-}
-
-#dangerOverlay {
- position: absolute;
- background-color: red;
- transition: all 0.2s ease;
- width: 100%;
- height: 100%;
- opacity: 0;
-}
-
-#playingfield {
- position: fixed;
- width: 100%;
- height: 200%;
- top: -100%;
-}
+} */
#clickareas {
position: absolute;
@@ -121,38 +99,6 @@
background-color: #7d7d7d4e;
}
-#grid {
- position: fixed;
- width: 100%;
- height: 100%;
-}
-
-#next {
- position: fixed;
- left: 101%;
- display: grid;
- grid-template-columns: repeat(4, 1fr);
- grid-template-rows: repeat(15, 1fr);
- height: 79%;
- width: 40%;
- border-radius: 0 1.5vh 1.5vh 0;
- outline: 0.2vh solid var(--cl-blue);
- background-color: black;
- transition: all 0.3s ease;
-}
-
-#hold {
- position: fixed;
- left: -40%;
- display: grid;
- grid-template-columns: repeat(4, 1fr);
- grid-template-rows: repeat(3, 1fr);
- height: 15%;
- width: 39.5%;
- border-radius: 1.5vh 0 0 1.5vh;
- background-color: black;
-}
-
#lockTimer,
#lockCounter {
position: absolute;
@@ -192,6 +138,9 @@
}
#climbSpeedBar {
+ /* css variables which can be changed with js */
+ --bar-colour: red;
+ --background-colour: #00000000;
position: absolute;
width: 32vh;
height: 1vh;
@@ -202,12 +151,13 @@
}
#climbSpeedBar::-webkit-progress-value {
- background-color: red;
+ background-color: var(--bar-colour);
border-radius: 0.7vh;
}
#climbSpeedBar::-webkit-progress-bar {
- background-color: var(--invis);
+ background-color: var(--background-colour);
+ border-radius: 0.7vh;
}
#timeLeftText {
@@ -382,16 +332,6 @@
}
}
-.nextText {
- left: 110%;
- bottom: 100%;
-}
-
-.holdText {
- right: 110%;
- bottom: 100%;
-}
-
.objectiveText {
left: 110%;
bottom: 10%;
diff --git a/styles/menus.css b/styles/menus.css
index 3b3a563..b03a189 100644
--- a/styles/menus.css
+++ b/styles/menus.css
@@ -271,24 +271,6 @@ button>img {
}
/* stats */
-
-.actiontext,
-.statstext {
- position: fixed;
- font-size: 3vh;
- text-shadow: 0 0 3vh var(--vl-gray);
- margin: 0;
- text-align: right;
- width: 200%;
- user-select: none;
- transition: all 0.2s ease;
- right: 105%;
-}
-
-.actiontext {
- opacity: 0;
-}
-
.smalltext {
position: absolute;
font-size: 0.9em;
@@ -296,23 +278,6 @@ button>img {
user-select: none;
}
-#smallStat1,
-#smallStat2,
-#smallStat3 {
- right: 150%;
- font-size: 2.1vh;
- text-align: right;
-}
-
-#statName1,
-#statName2,
-#statName3 {
- text-align: right;
- right: 105%;
- transform: translateY(0.5vh);
-}
-
-.statText,
#explanationText,
#updatetext {
display: flex;
@@ -322,6 +287,8 @@ button>img {
.statText {
opacity: 1;
+ display: flex;
+ margin: 0.5vmin;
}
/* focus */
diff --git a/styles/settings.css b/styles/settings.css
index 3937a09..371372c 100644
--- a/styles/settings.css
+++ b/styles/settings.css
@@ -154,7 +154,6 @@
right: 1vw;
bottom: 1vh;
padding: 1vh;
- padding-top: 1.5vh;
display: flex;
justify-content: center;
align-items: center;
diff --git a/styles/style.css b/styles/style.css
index 72980c8..8dce86e 100644
--- a/styles/style.css
+++ b/styles/style.css
@@ -56,46 +56,6 @@ body {
transition: all 1s ease;
}
-#openSettingsButton,
-#editButton {
- top: 5%;
- position: fixed;
- left: 127%;
- display: flex;
- justify-content: right;
- padding-right: 3%;
- align-items: center;
- height: 8%;
- width: 24%;
- border: 0.2vh solid white;
- border-radius: 0 1.5vh 1.5vh 0;
- transition: all 0.5s ease-out;
- background-color: var(--invis);
- outline: none;
- opacity: 0.6;
-}
-
-#editButton {
- top: 15%;
-}
-
-#openSettingsButton:hover,
-#editButton:hover {
- left: 133%;
- opacity: 1;
- transition: all 0.2s ease;
-}
-
-#openSettingsButton>img {
- height: 70%;
- user-select: none;
-}
-
-#editButton>img {
- height: 100%;
- user-select: none;
-}
-
.dialog img,
.scrollSettings img {
opacity: 0.6;
From 2c9c3bec52f2ddb7ffe712cc6661d6248e52433b Mon Sep 17 00:00:00 2001
From: TitanPlayz <118145727+TitanPlayz100@users.noreply.github.com>
Date: Tue, 29 Oct 2024 22:59:14 +1100
Subject: [PATCH 4/6] added final bits of pixi text, fixed animations, changed
key presses to be queued
---
index.html | 35 ++---
info.md | 10 +-
src/data/defaultSettings.json | 3 +-
src/data/gamemodes.json | 3 +-
src/display/boardEffects.js | 14 +-
src/display/particles.js | 2 +-
src/display/pixirender.js | 133 ++++++++++++++++---
src/display/renderer.js | 42 +++---
src/features/editboard.js | 62 +++------
src/features/history.js | 9 +-
src/features/modes.js | 1 -
src/features/profileStats.js | 5 +-
src/features/sounds.js | 1 -
src/game.js | 4 +-
src/main.js | 11 +-
src/mechanics/clearlines.js | 1 +
src/mechanics/locking.js | 6 +-
src/movement/controls.js | 30 +++--
styles/boards.css | 241 ++--------------------------------
styles/menus.css | 23 ++--
styles/style.css | 1 -
21 files changed, 248 insertions(+), 389 deletions(-)
diff --git a/index.html b/index.html
index 584ed06..5fc10e2 100644
--- a/index.html
+++ b/index.html
@@ -1,39 +1,33 @@
+ teti
- teti
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
⚠ GO DOWN
-
60S LEFT
-
-
-
history: 0
-
-
- 1
- 2
-
-
+
Teti
@@ -43,6 +37,12 @@
Teti
OUT OF FOCUSClick To Return
+
+
@@ -127,6 +127,7 @@ Teti
+
diff --git a/info.md b/info.md
index 4811fcc..cb5ac74 100644
--- a/info.md
+++ b/info.md
@@ -69,6 +69,11 @@ Skins from [YHF](https://you.have.fail/ed/at/tetrioplus/)
Things that I am working on based on other changes
- ready set go start option
- arcade mode
+- rotation centres
+
+- CHANGE GAME CLASS TO BE EXPORTED MODULES
+ - remove all this.game references in replacement with just the class being imported
+ - **no longer shall the shackles of past object oriented java code bound the multiparadigm eutopia which is javascript**
Zenith mode additions
- add fatigue:
@@ -97,7 +102,6 @@ Khaki (#ffc48e)
"Soft Pink" (#ffbbea)
White (#ffffff)
-
***
## Updates
@@ -109,6 +113,10 @@ White (#ffffff)
- changed PC text to be more TETR.IO-like
- changed spike text to show in the middle of the board (like techmino)
- RIP coloured queues
+- better page loading using defer and lazy loading
+- Experimental: pressed keys are stored in a queue, and evry pixi tick they all fire, might be more responsive
+- changed timeLeftText animation to use gsap and pixi
+- added setting for toggling action text
#### v1.3.4 => PIXI.js
- COMPLETE REWRITE OF ALL GRAPHICS
diff --git a/src/data/defaultSettings.json b/src/data/defaultSettings.json
index 13b626f..44c952a 100644
--- a/src/data/defaultSettings.json
+++ b/src/data/defaultSettings.json
@@ -15,7 +15,8 @@
"particles":true,
"particleVolume": 60,
"particleSize":1,
- "skin":"tetrio"
+ "skin":"tetrio",
+ "actionText": true
},
"game": {
"gravitySpeed": 950,
diff --git a/src/data/gamemodes.json b/src/data/gamemodes.json
index edb901a..418885b 100644
--- a/src/data/gamemodes.json
+++ b/src/data/gamemodes.json
@@ -14,7 +14,8 @@
"allspinminis": false,
"history": false,
"sidebar": ["time", "apm", "pps"],
- "stride": false
+ "stride": false,
+ "clearDelay": 0
},
"displayName": "Unset",
"objectiveText": "",
diff --git a/src/display/boardEffects.js b/src/display/boardEffects.js
index 7d82384..96bde5f 100644
--- a/src/display/boardEffects.js
+++ b/src/display/boardEffects.js
@@ -18,8 +18,6 @@ export class BoardEffects {
paceCooldown = 0;
divBoard = document.getElementById("board");
- // border = document.getElementById('backborder')
- // backboard = document.getElementById('backboard')
/**
*
@@ -49,7 +47,6 @@ export class BoardEffects {
this.Y = this.clamp(this.Y, 0.5);
if (this.X != 0 || this.Y != 0) {
- this.divBoard.style.translate = `${this.X}px ${this.Y}px`
this.game.pixi.app.canvas.style.translate = `${this.X}px ${this.Y}px`
}
}
@@ -65,7 +62,6 @@ export class BoardEffects {
this.R = this.clamp(this.R, 0.1);
if (this.R != 0) {
- this.divBoard.style.rotate = `${this.R}deg`
this.game.pixi.app.canvas.style.rotate = `${this.R}deg`
}
}
@@ -100,10 +96,10 @@ export class BoardEffects {
}
toggleRainbow(pace) {
- return;
- this.border.style.setProperty('--blur-size', pace ? `0.3vmin` : `0vmin`)
- this.border.style.setProperty('--blur-strength', pace ? '0.7vmin' : '0')
- this.backboard.style.setProperty('--blur-strength', pace ? '0.5vmin' : '0')
- this.hasPace = pace;
+ // todo add back
+ // this.border.style.setProperty('--blur-size', pace ? `0.3vmin` : `0vmin`)
+ // this.border.style.setProperty('--blur-strength', pace ? '0.7vmin' : '0')
+ // this.backboard.style.setProperty('--blur-strength', pace ? '0.5vmin' : '0')
+ // this.hasPace = pace;
}
}
\ No newline at end of file
diff --git a/src/display/particles.js b/src/display/particles.js
index b7253f4..1cb236a 100644
--- a/src/display/particles.js
+++ b/src/display/particles.js
@@ -202,7 +202,7 @@ export class Particles {
const posX = (direction ? 0 : width) + x + Math.random() * len
const posY = y + Math.random() * height;
const life = Math.random() * 25 + 50;
- const dx = (direction ? 1 : -1) * (Math.random() * 2);
+ const dx = (direction ? -1 : 1) * (Math.random() * 2);
const dy = Math.random() * 2 - 1;
const BTBParticle = { x: posX, y: posY, colour, life, dx, dy, gravity: 0.15 }
diff --git a/src/display/pixirender.js b/src/display/pixirender.js
index 20e3b77..5604c32 100644
--- a/src/display/pixirender.js
+++ b/src/display/pixirender.js
@@ -14,6 +14,7 @@ export class PixiRender {
justPlacedAlpha = 1;
shadowSprites = {};
editButtonVisible = false;
+ currentlyFlashing = {}
divlock = document.getElementById("lockTimer");
@@ -27,7 +28,7 @@ export class PixiRender {
async init() {
this.app = new PIXI.Application();
await this.app.init({ backgroundAlpha: 0, resizeTo: window, autoDensity: true });
- document.body.appendChild(this.app.canvas);
+ document.body.prepend(this.app.canvas);
// grid
const grid = new PIXI.Container();
@@ -39,6 +40,10 @@ export class PixiRender {
this.app.stage.addChild(this.board);
this.board.label = "board";
+ const clickArea = new PIXI.Container();
+ this.app.stage.addChild(clickArea);
+ clickArea.label = "clickArea";
+
const next = new PIXI.Container();
this.app.stage.addChild(next);
next.label = "next";
@@ -77,12 +82,15 @@ export class PixiRender {
const next = this.app.stage.getChildByLabel("next");
const hold = this.app.stage.getChildByLabel("hold");
const board = this.app.stage.getChildByLabel("board");
+ const clickArea = this.app.stage.getChildByLabel("clickArea");
const particles = this.app.stage.getChildByLabel("particles");
const textContainer = this.app.stage.getChildByLabel("textContainer");
// clear
grid.children.forEach(child => child.destroy());
grid.removeChildren();
+ clickArea.children.forEach(child => child.destroy());
+ clickArea.removeChildren();
textContainer.removeChildren();
// resize
@@ -103,6 +111,8 @@ export class PixiRender {
board.pivot.x = width / 2;
board.pivot.y = height * 3 / 2;
+
+
// hold
const clickRectHold = new PIXI.Graphics().rect(0, 0, width * 2 / 5, height * 3 / 20).fill("transparent");
clickRectHold.interactive = true;
@@ -127,15 +137,25 @@ export class PixiRender {
next.pivot.x = width / 2 - width * 11 / 10;
next.pivot.y = height / 2;
+ const rect2 = new PIXI.Graphics().rect(0, 0, width, height).fill("transparent");
+ rect2.interactive = true;
+ rect2.cursor = 'pointer'
+ rect2.on("pointerdown", () => console.log("click"));
+ clickArea.addChild(rect2);
+ clickArea.x = screenWidth;
+ clickArea.y = screenHeight;
+ clickArea.pivot.x = width / 2;
+ clickArea.pivot.y = height / 2;
+
// grid and outline
const { textHold, textNext } = this.textGraphics(width);
const { settings, reset, edit } = this.buttonGraphics(width);
- this.boardBG = new PIXI.Graphics()
+ this.boardDanger = new PIXI.Graphics()
.rect(0, 0, width, height)
.fill("red")
- this.boardBG.alpha = 0;
- grid.addChild(this.boardBG);
+ this.boardDanger.alpha = 0;
+ grid.addChild(this.boardDanger);
this.border = new PIXI.Graphics()
.lineTo(0, height).lineTo(width, height).lineTo(width, 0)
@@ -156,8 +176,8 @@ export class PixiRender {
rectNext.x = width;
grid.addChild(textNext);
- grid.addChild(settings);
grid.addChild(reset);
+ grid.addChild(settings);
grid.addChild(edit);
this.editButton = edit;
@@ -183,6 +203,7 @@ export class PixiRender {
textContainer.addChild(this.actionTexts.btbtext.sprite)
textContainer.addChild(this.actionTexts.spiketext.sprite)
textContainer.addChild(this.actionTexts.pctext.sprite)
+ textContainer.addChild(this.actionTexts.timeleft.sprite)
this.statTexts.forEach((text) => {
textContainer.addChild(text.stat);
textContainer.addChild(text.statText);
@@ -193,6 +214,7 @@ export class PixiRender {
this.generateGrid();
this.resetAnimGraphic();
+ this.generateClickMinos(clickArea);
}
// TEXT
@@ -227,6 +249,14 @@ export class PixiRender {
pcText.pivot.x = pcText.width / 2 - 10;
pcText.pivot.y = pcText.height / 2;
+ const timeLeftStyle = new PIXI.TextStyle({ fontFamily: "Montserrat", fontSize: 20, fill: "gold", fontWeight: "bold" });
+ const timeLeftText = new PIXI.Text({ text: "", style: timeLeftStyle });
+ timeLeftText.resolution = 2;
+ timeLeftText.alpha = 0;
+ timeLeftText.x = this.width / 2;
+ timeLeftText.y = this.height * 1 / 8;
+ timeLeftText.anchor.x = 0.5;
+
const spiketext = actionText(3);
spiketext.sprite.x = this.width / 2;
spiketext.sprite.y = this.height * 1 / 4;
@@ -238,7 +268,8 @@ export class PixiRender {
combotext: actionText(1),
btbtext: actionText(2),
spiketext,
- pctext: { sprite: pcText, animation: gsap.timeline() }
+ pctext: { sprite: pcText, animation: gsap.timeline() },
+ timeleft: { sprite: timeLeftText, animation: gsap.timeline() }
}
const statStyle = new PIXI.TextStyle({ fontFamily: "Major Mono Display", fontSize: 16, fill: "white", fontWeight: "bold" });
@@ -268,18 +299,32 @@ export class PixiRender {
const objectiveText = new PIXI.Text({ text: "", style: statSecondaryStyle });
objectiveText.resolution = 2;
- objectiveText.position.set(width*11/10, this.height - this.height * 3 / 40)
+ objectiveText.position.set(width * 11 / 10, this.height - this.height * 3 / 40)
const objectiveNameText = new PIXI.Text({ text: "", style: statTextStyle });
objectiveNameText.resolution = 2;
- objectiveNameText.position.set(width*11/10, this.height - this.height * 5/40)
+ objectiveNameText.position.set(width * 11 / 10, this.height - this.height * 5 / 40)
this.objectiveTexts = [objectiveText, objectiveNameText];
return { textHold, textNext };
}
- // todo reset action text
+ resetActionTexts() {
+ Object.keys(this.actionTexts).forEach(key => {
+ this.actionTexts[key].animation.pause();
+ gsap.to(this.actionTexts[key].sprite, {
+ duration: 0.2, pixi: { alpha: 0 },
+ onComplete: () => this.actionTexts[key].animation.kill()
+ })
+ })
+ if (this.timeLeftTextSplit) this.timeLeftTextSplit.forEach(s => {
+ s.animation.kill();
+ s.sprite.destroy();
+ });
+ this.timeLeftTextSplit = undefined;
+ }
+
showActionText(type, message) {
this.actionTexts[type].animation.kill();
const text = this.actionTexts[type].sprite;
@@ -318,6 +363,23 @@ export class PixiRender {
.to(pc, { duration: 2.5, pixi: { scale: 0, alpha: 0 }, ease: "power3.in" }, "1.5")
}
+ showTimeLeftText(msg) {
+ const textContainer = this.app.stage.getChildByLabel("textContainer");
+ this.actionTexts.timeleft.animation.kill();
+ const text = this.actionTexts.timeleft.sprite;
+ text.text = msg;
+ const split = this.splitSprite(text)
+ this.timeLeftTextSplit = split.map((s, i) => {
+ textContainer.addChild(s);
+ const animation = gsap.timeline({ onComplete: () => s.destroy() })
+ .to(s, { duration: 0, pixi: { alpha: 1, x: s.x, tint: "white" } })
+ .to(s, { duration: 3, pixi: { x: s.x + 8 * (i - split.length / 2) } })
+ .to(s, { duration: 3 / 20, pixi: { tint: "red" }, repeat: 20, yoyo: true, ease: "none" }, "0")
+ .to(s, { duration: 0.5, pixi: { alpha: 0 } }, "2.5")
+ return { sprite: s, animation }
+ });
+ }
+
// GRAPHICS and GENERATORS
buttonGraphics(width) {
const iconframe = (texture, scale, y) => {
@@ -333,12 +395,10 @@ export class PixiRender {
return icon
}
- const settings = iconframe(this.settingsIcon, 0.18, 0)
- settings.on("pointerdown", () => this.game.modals.openModal("settingsPanel"));
-
- const reset = iconframe(this.resetIcon, 0.23, width * 3 / 20)
+ const reset = iconframe(this.resetIcon, 0.23, 0)
reset.on("pointerdown", () => this.game.controls.retry(true));
-
+ const settings = iconframe(this.settingsIcon, 0.18, width * 3 / 20)
+ settings.on("pointerdown", () => this.game.modals.openModal("settingsPanel"));
const edit = iconframe(this.editIcon, 0.21, width * 6 / 20)
edit.on("pointerdown", () => this.game.modals.openModal("editMenu"));
edit.visible = this.editButtonVisible
@@ -408,6 +468,21 @@ export class PixiRender {
this.shadowSprites[type] = shadowArray
}
+ generateClickMinos(clickArea) {
+ for (let y = 0; y < 20; y++) {
+ for (let x = 0; x < 10; x++) {
+ const mino = new PIXI.Sprite(this.textures['g']);
+ mino.interactive = true;
+ mino.on("mousedown", () => this.game.boardeditor.mouseDown([x, y], mino));
+ mino.on("mouseenter", () => this.game.boardeditor.mouseEnter([x, y], mino));
+ mino.on("mouseleave", () => this.game.boardeditor.mouseLeave([x, y], mino));
+ clickArea.addChild(mino);
+ mino.position.set(x * this.minoSize, y * this.minoSize);
+ mino.setSize(this.minoSize);
+ mino.alpha = 0;
+ }
+ }
+ }
generateGrid() {
if (this.game.settings.display.showGrid === false) return;
@@ -440,6 +515,7 @@ export class PixiRender {
// RENDER CLOCK
tick(time) {
+ this.game.controls.runKeyQueue();
this.render("board", this.game.board.boardState);
this.game.boardeffects.move(0, 0);
this.game.boardeffects.rotate(0);
@@ -489,7 +565,6 @@ export class PixiRender {
return this.textures[piece];
}
- // todo remove flash for cleared lines
flash(coords) {
coords.forEach(([x, y]) => {
const triangle = new PIXI.Sprite(this.triangle);
@@ -497,12 +572,17 @@ export class PixiRender {
triangle.y = (39 - y) * this.minoSize;
triangle.label = "invincible";
this.board.addChild(triangle);
- gsap.timeline({ onComplete: () => this.board.removeChild(triangle) })
+ this.currentlyFlashing[`${x},${y}`] = gsap.timeline({ onComplete: () => this.board.removeChild(triangle) })
.to(triangle, { duration: 0, pixi: { width: this.minoSize, height: this.minoSize } })
.to(triangle, { duration: 0.15, pixi: { width: 0, height: 0 }, ease: "power1.inOut", })
})
}
+ endFlash([x, y]) {
+ const a = this.currentlyFlashing[`${x},${y}`];
+ a.totalProgress(1).kill();
+ }
+
getOpacity(cell, type, x, y) {
if (type != "board") return;
if (this.divlock.value != 0 && cell.includes("A") && this.game.settings.game.gamemode != "lookahead") {
@@ -553,7 +633,7 @@ export class PixiRender {
}
toggleDangerBG(danger) {
- gsap.to(this.boardBG, { duration: 0.2, pixi: { alpha: danger ? 0.1 : 0 } });
+ gsap.to(this.boardDanger, { duration: 0.2, pixi: { alpha: danger ? 0.1 : 0 } });
gsap.to(this.border, { duration: 0.2, pixi: { tint: danger ? "red" : "none" } });
}
@@ -586,4 +666,23 @@ export class PixiRender {
this.board.removeChild(this.resetMask);
this.board.removeChild(this.resetTriangle);
}
+
+ /** @param {PIXI.Text} textSprite */
+ splitSprite(textSprite) {
+ const target = textSprite;
+ const textContent = textSprite.text;
+ let currentX = target.x - target.width / 2;
+ target.text = "";
+ const textChars = textContent.split("");
+ /**@type {PIXI.Text[]} */
+ let chars = []
+ textChars.forEach((char) => {
+ const charSprite = new PIXI.Text({ text: char, style: target.style });
+ charSprite.x = currentX;
+ charSprite.y = target.y;
+ currentX += charSprite.width;
+ chars.push(charSprite);
+ });
+ return chars
+ }
}
diff --git a/src/display/renderer.js b/src/display/renderer.js
index 53c6610..a97b508 100644
--- a/src/display/renderer.js
+++ b/src/display/renderer.js
@@ -74,13 +74,13 @@ export class Renderer {
this.inDanger = condition;
}
- renderActionText(damagetype, isBTB, isPC, damage, linecount) {
- if (damagetype != "") this.game.pixi.showActionText("cleartext", damagetype);
- if (this.game.stats.combo > 0) this.game.pixi.showActionText("combotext", `Combo ${this.game.stats.combo}`);
- if (isBTB && this.game.stats.btbCount > 0) this.game.pixi.showActionText("btbtext", `btb ${this.game.stats.btbCount} `);
- if (this.game.mechanics.spikeCounter > 4) this.game.pixi.showSpikeText(`${this.game.mechanics.spikeCounter}`);
- if (isPC) this.game.pixi.showPCText();
+ dangerParticles() {
+ if (!this.inDanger) return;
+ this.game.particles.spawnParticles(0, 0, "dangerboard");
+ this.game.particles.spawnParticles(0, 20, "dangersides");
+ }
+ renderActionText(damagetype, isBTB, isPC, damage, linecount) {
// audio
if (isPC) this.game.sounds.playSound("allclear");
if (this.game.stats.btbCount == 2 && isBTB) this.game.sounds.playSound("btb_1");
@@ -98,11 +98,15 @@ export class Renderer {
if (this.game.mechanics.spikeCounter >= 15) this.game.sounds.playSound("thunder", false);
if (this.game.stats.combo > 0)
this.game.sounds.playSound(`combo_${this.game.stats.combo > 16 ? 16 : this.game.stats.combo}`);
- }
- stopTimeout(name) {
- clearTimeout(this.texttimeouts[name]);
- this.texttimeouts[name] = 0;
+ // text
+ if (this.game.settings.display.actionText == false) return;
+ if (damagetype != "") this.game.pixi.showActionText("cleartext", damagetype);
+ if (this.game.stats.combo > 0) this.game.pixi.showActionText("combotext", `Combo ${this.game.stats.combo}`);
+ if (isBTB && this.game.stats.btbCount > 0) this.game.pixi.showActionText("btbtext", `btb ${this.game.stats.btbCount} `);
+ if (this.game.mechanics.spikeCounter > 4 && linecount > 0) this.game.pixi.showSpikeText(`${this.game.mechanics.spikeCounter}`);
+ if (isPC) this.game.pixi.showPCText();
+
}
renderStyles(settings = false) {
@@ -115,6 +119,7 @@ export class Renderer {
const height = Number(this.game.settings.display.boardHeight);
this.divBoard.style.transform = `scale(${height}%) translate(-50%, -50%)`;
+ // todo add board background
// board opacity
// const background = `rgba(0, 0, 0, ${Number(this.game.settings.display.boardOpacity) / 100})`;
// this.divBackboard.style.backgroundColor = background;
@@ -168,16 +173,7 @@ export class Renderer {
}
renderTimeLeft(text){
- const e = document.getElementById("timeLeftText")
- if (this.texttimeouts["timeLeft"] != 0){
- this.stopTimeout("timeLeft");
- //e.classList.remove("warn");
- }
- e.textContent = text
- e.classList.add("warn")
- this.texttimeouts["timeLeft"] = setTimeout(() => {
- e.classList.remove("warn");
- }, 3000);
+ this.game.pixi.showTimeLeftText(text);
}
setEditPieceColours() {
@@ -199,10 +195,4 @@ export class Renderer {
const forces = { "CW": force, "CCW": -force }
this.game.boardeffects.rotate(forces[type]);
}
-
- dangerParticles() {
- if (!this.inDanger) return;
- this.game.particles.spawnParticles(0, 0, "dangerboard");
- this.game.particles.spawnParticles(0, 20, "dangersides");
- }
}
diff --git a/src/features/editboard.js b/src/features/editboard.js
index 8a7878f..c89c5f0 100644
--- a/src/features/editboard.js
+++ b/src/features/editboard.js
@@ -1,7 +1,6 @@
import { Game } from "../game.js";
export class BoardEditor {
- // clickareasdiv = document.getElementById("clickareas");
mousedown = false;
currentMode = "fill";
fillPiece = 'G';
@@ -16,51 +15,28 @@ export class BoardEditor {
this.board = game.board;
}
- addListeners() {
- // delegate listeners for efficiency
- document.body.addEventListener("mousedown", (e) => {
- if (e.target.classList.contains('clickmino')) {
- const j = Number(e.target.dataset.x)
- const i = Number(e.target.dataset.y)
- if (this.game.settings.game.gamemode != 'custom') return;
- if (this.fillRow) { this.fillWholeRow([j, 19 - i]) }
- else { this.fillCell([j, 19 - i]); }
- }
- });
-
- document.body.addEventListener("mouseenter", (e) => {
- if (e.target.classList.contains('clickmino')) {
- const j = Number(e.target.dataset.x)
- const i = Number(e.target.dataset.y)
- if (this.game.settings.game.gamemode != 'custom') return;
- e.target.classList.add('highlighting')
- if (this.mousedown) {
- if (this.fillRow) { this.fillWholeRow([j, 19 - i]) }
- else { this.fillCell([j, 19 - i]); }
- }
- }
- }, true);
+ mouseDown([x, y], sprite) {
+ if (this.game.settings.game.gamemode != 'custom') return;
+ if (this.fillRow) { this.fillWholeRow([x, 19 - y]) }
+ else { this.fillCell([x, 19 - y]); }
+ }
- document.body.addEventListener("mouseleave", (e) => {
- if (e.target.classList.contains('clickmino')) {
- e.target.classList.remove('highlighting')
- }
- }, true);
+ mouseEnter([x, y], sprite) {
+ if (this.game.settings.game.gamemode != 'custom') return;
+ sprite.alpha = 0.5;
+ if (this.mousedown) {
+ if (this.fillRow) { this.fillWholeRow([x, 19 - y]) }
+ else { this.fillCell([x, 19 - y]); }
+ }
+ }
- document.body.addEventListener("mouseup", () => {
- if (this.mousedown) this.game.history.save();
- this.mousedown = false;
- });
+ mouseLeave(e, sprite) {
+ sprite.alpha = 0;
+ }
- for (let i = 0; i < 20; i++) {
- for (let j = 0; j < 10; j++) {
- const clickarea = document.createElement("div");
- clickarea.classList.add("clickmino");
- clickarea.dataset.x = j.toString();
- clickarea.dataset.y = i.toString();
- this.clickareasdiv.appendChild(clickarea);
- }
- }
+ mouseUp(e) {
+ if (this.mousedown) this.game.history.save();
+ this.mousedown = false;
}
fillCell([x, y]) {
diff --git a/src/features/history.js b/src/features/history.js
index 2df0386..434e91d 100644
--- a/src/features/history.js
+++ b/src/features/history.js
@@ -86,7 +86,7 @@ export class History {
updateUI() {
const branches = this.historyConnections[this.currentState] ?? [];
this.selectedbranch = Math.max(...branches);
- this.historyelement.textContent = `history: ${this.currentState}`;
+ this.historyelement.textContent = `current: ${this.currentState}`;
if (branches.length <= 1) {
this.choiceselement.style.opacity = "0";
this.choiceselement.style.pointerEvents = "none";
@@ -96,7 +96,7 @@ export class History {
this.choiceselement.style.opacity = "1";
this.choiceselement.style.pointerEvents = "all";
- [...this.choiceselement.children].forEach(button => button.remove())
+ [...document.getElementsByClassName("redochoice")].forEach(button => button.remove())
branches.forEach(state => {
const button = document.createElement("button");
button.classList.add("redochoice");
@@ -183,9 +183,4 @@ export class History {
this.game.hold.piece = this.game.renderer.getPiece(hold);
this.game.mechanics.spawnPiece(this.game.bag.randomiser());
}
-
- setHistoryDiv(bool) {
- this.historyelement.style.display = bool ? "block" : "none";
- }
-
}
\ No newline at end of file
diff --git a/src/features/modes.js b/src/features/modes.js
index 5a9cdce..bbf6c72 100644
--- a/src/features/modes.js
+++ b/src/features/modes.js
@@ -63,7 +63,6 @@ export class Modes {
this.setGamemode(currentGamemode);
this.game.pixi.objectiveTexts[1].text = this.modeJSON.objectiveText.toUpperCase();
- this.game.history.setHistoryDiv(this.game.settings.game.gamemode == 'custom');
this.game.pixi.toggleEditButton(this.game.settings.game.gamemode == 'custom');
}
diff --git a/src/features/profileStats.js b/src/features/profileStats.js
index 4427eb4..2028fb2 100644
--- a/src/features/profileStats.js
+++ b/src/features/profileStats.js
@@ -4,6 +4,7 @@ import { Game } from "../game.js";
export class ProfileStats {
personalBests = {};
notSaved = ['game', 'level', 'combo']
+ elementGameEndTitle = document.getElementById("gameEndTitle");
/**
* @param {Game} game
@@ -13,7 +14,7 @@ export class ProfileStats {
}
setPB(score) {
- this.game.elementGameEndTitle.textContent = 'GAME ENDED';
+ this.elementGameEndTitle.textContent = 'GAME ENDED';
const gamemode = this.game.settings.game.gamemode
const gamemodeStats = this.personalBests[gamemode] ?? {};
const currentScore = Number(gamemodeStats.score);
@@ -28,7 +29,7 @@ export class ProfileStats {
gameStatsKeys.forEach(key => gameStats[key] = this.game.stats[key])
const ts = new Date().toJSON();
this.personalBests[gamemode] = { score, pbstats: gameStats, version: this.game.version, ts };
- this.game.elementGameEndTitle.textContent = 'NEW PB!';
+ this.elementGameEndTitle.textContent = 'NEW PB!';
setTimeout(() => this.game.sounds.playSound("personalbest"), 1000);
this.game.modals.generate.notif("PB Saved", `PB on ${gamemode} saved`, "success");
diff --git a/src/features/sounds.js b/src/features/sounds.js
index a29eb51..43f357f 100644
--- a/src/features/sounds.js
+++ b/src/features/sounds.js
@@ -111,7 +111,6 @@ export class Sounds {
track.connect(this.lowpassfilter);
this.lowpassfilter.connect(this.audioContext.destination);
})
- // this.playSound("allclear") // i knew it was a bad idea
}
setAudioLevel() {
diff --git a/src/game.js b/src/game.js
index d1f7fb1..b339485 100644
--- a/src/game.js
+++ b/src/game.js
@@ -26,7 +26,7 @@ export class Game {
gameTimer = 0; // id of timeout
survivalTimer = 0; // id of timeout
gravityTimer = 0;
- version = '1.3.4';
+ version = '1.3.5';
tickrate = 60;
elementReason = document.getElementById("reason");
@@ -68,7 +68,6 @@ export class Game {
this.renderer.setEditPieceColours();
this.sounds.initSounds();
this.startGame();
- // this.boardeditor.addListeners();
this.menuactions.addRangeListener();
this.modals.generate.addMenuListeners();
this.modals.generate.generateGamemodeMenu();
@@ -136,6 +135,7 @@ export class Game {
this.particles.clearParticles();
this.renderer.clearHold();
this.stopGameTimers();
+ this.pixi.resetActionTexts();
this.bag = new Bag(this);
this.mechanics = new Mechanics(this);
diff --git a/src/main.js b/src/main.js
index c9c99c6..8aeba31 100644
--- a/src/main.js
+++ b/src/main.js
@@ -7,9 +7,6 @@ window["menu"] = game.menuactions;
window["modal"] = game.modals;
window["songs"] = game.sounds;
-const elementSplashScreen = document.getElementById("splashScreen");
-const elementSplashText = document.getElementById("splashText");
-
window.addEventListener("keydown", event => {
if (event.key == undefined) return;
let key = event.key.length > 1 ? event.key : event.key.toLowerCase(); // 1 letter words are lowercase
@@ -21,7 +18,6 @@ window.addEventListener("keydown", event => {
game.controls.onKeyDown(event, key);
});
-
window.addEventListener("keyup", event => {
if (event.key == undefined) return;
let key = event.key.length > 1 ? event.key : event.key.toLowerCase();
@@ -32,6 +28,10 @@ window.addEventListener('mousemove', () => {
game.controls.toggleCursor(true);
})
+document.body.addEventListener("mouseup", (e) => {
+ game.boardeditor.mouseUp(e);
+});
+
window.addEventListener("resize", () => {
setTimeout(() => {
game.pixi.resize();
@@ -40,6 +40,9 @@ window.addEventListener("resize", () => {
}, 0);
})
+
+const elementSplashScreen = document.getElementById("splashScreen");
+const elementSplashText = document.getElementById("splashText");
export function clearSplash() {
elementSplashText.textContent = "Ready";
elementSplashScreen.style.opacity = 0;
diff --git a/src/mechanics/clearlines.js b/src/mechanics/clearlines.js
index f342c87..6288322 100644
--- a/src/mechanics/clearlines.js
+++ b/src/mechanics/clearlines.js
@@ -24,6 +24,7 @@ export class ClearLines {
removedGarbage++;
stopped.filter(c => c[1] == row).forEach(([x, y]) => { // clear rows
this.game.mechanics.board.setCoordEmpty([x, y]);
+ this.game.pixi.endFlash([x, y]);
});
this.game.mechanics.board.moveMinos(stopped.filter(c => c[1] > row), "DOWN", 1);
}
diff --git a/src/mechanics/locking.js b/src/mechanics/locking.js
index 596a776..b307170 100644
--- a/src/mechanics/locking.js
+++ b/src/mechanics/locking.js
@@ -110,11 +110,13 @@ export class LockPiece {
this.game.renderer.renderDanger();
const delay = (cleared > 0) ? this.game.settings.game.clearDelay : 0;
- this.timings.clearDelay = setTimeout(() => {
+ const onClear = () => {
this.game.mechanics.spawnPiece(this.game.bag.randomiser());
this.game.history.save();
this.timings.clearDelay = 0;
- }, delay);
+ }
+ if (delay == 0) onClear();
+ else this.timings.clearDelay = setTimeout(() => onClear(), delay);
}
clearLockDelay(clearCount = true) {
diff --git a/src/movement/controls.js b/src/movement/controls.js
index 08734d0..248ab50 100644
--- a/src/movement/controls.js
+++ b/src/movement/controls.js
@@ -11,6 +11,8 @@ export class Controls {
cursorVisible = true;
resetting = false;
+ keyQueue = [];
+
/**
* @param {Game} game
*/
@@ -31,19 +33,26 @@ export class Controls {
if (key == keys.resetKey) this.retry(true);
if (this.game.ended) return;
- if (key == keys.cwKey) this.moves.rotate("CW");
- else if (key == keys.ccwKey) this.moves.rotate("CCW");
- else if (key == keys.rotate180Key) this.moves.rotate("180");
- else if (key == keys.hdKey) this.moves.harddrop();
- else if (key == keys.holdKey) this.game.mechanics.switchHold();
- else if (key == keys.rightKey) this.startDas("RIGHT");
- else if (key == keys.leftKey) this.startDas("LEFT");
- else if (key == keys.sdKey) this.startArrSD();
-
+ this.keyQueue.push(key);
this.toggleCursor(false);
this.game.stats.inputs++;
}
+ runKeyQueue() {
+ const keys = this.game.settings.control;
+ this.keyQueue.forEach(key => {
+ if (key == keys.cwKey) this.moves.rotate("CW");
+ else if (key == keys.ccwKey) this.moves.rotate("CCW");
+ else if (key == keys.rotate180Key) this.moves.rotate("180");
+ else if (key == keys.hdKey) this.moves.harddrop();
+ else if (key == keys.holdKey) this.game.mechanics.switchHold();
+ else if (key == keys.rightKey) this.startDas("RIGHT");
+ else if (key == keys.leftKey) this.startDas("LEFT");
+ else if (key == keys.sdKey) this.startArrSD();
+ });
+ this.keyQueue = [];
+ }
+
onKeyDownRepeat(event, key) { // allows for arr undo/redo
const keys = this.game.settings.control;
if (event.key == this.menuKey) event.preventDefault();
@@ -65,8 +74,7 @@ export class Controls {
this.directionState[direction] = "das";
this.stopTimeout("das");
this.stopInterval("arr");
- this.timings.das = setTimeout(() =>
- Promise.resolve().then(() => this.startArr(direction)), // feels faster with promise but idk
+ this.timings.das = setTimeout(() => this.startArr(direction),
this.game.settings.handling.das
);
}
diff --git a/styles/boards.css b/styles/boards.css
index 9c4dda7..35ff511 100644
--- a/styles/boards.css
+++ b/styles/boards.css
@@ -6,97 +6,7 @@
transform: scale(1.1) translate(-50%, -50%);
height: 60vh;
aspect-ratio: 0.5;
-}
-/*
-#backboard,
-#backborder {
- position: absolute;
- height: 100%;
- width: 100%;
- background-color: var(--background);
- outline: 0.2vh solid var(--cl-blue);
- box-shadow: 0 0 5vh var(--l-gray);
-}
-
-@property --angle {
- syntax: "";
- initial-value: 0deg;
- inherits: false;
-}
-
-#backboard {
- --blur-size: 7vmin;
- --spin-speed: 6s;
- --blur-radius: 20vmin;
- --blur-strength: 0;
- --colours: #ff4545, #00ff99, #006aff, #ff0095, #ff4545;
-}
-
-#backborder {
- --blur-size: 0.3vmin;
- --spin-speed: 2s;
- --blur-radius: 0.3vmin;
- --blur-strength: 0;
- --colours: #ff4545, #00ff99, #006aff, #ff0095, #ff4545;
-}
-
-#backboard::before,
-#backborder::before {
- content: " ";
- position: absolute;
- width: 100%;
- height: 100%;
- background-image: conic-gradient(from var(--angle), var(--colours));
- padding: var(--blur-size);
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- border-radius: 1vmin;
- animation: var(--spin-speed) spin linear infinite;
- filter: blur(var(--blur-radius));
- opacity: var(--blur-strength);
- transition: all 1s ease;
-}
-
-#backboard {
- outline: none;
-}
-
-@keyframes spin {
- from {
- --angle: 0deg;
- }
-
- to {
- --angle: 360deg;
- }
-}
-
-#backboard::after,
-#backborder::after {
- content: " ";
- position: absolute;
- width: 100%;
- height: 100%;
- background-color: var(--background);
-} */
-
-#clickareas {
- position: absolute;
- width: 100%;
- height: 100%;
- display: grid;
- grid-template-columns: repeat(10, 1fr);
- grid-template-rows: repeat(20, 1fr);
-}
-
-.clickmino {
- user-select: none;
- z-index: 10;
-}
-
-.highlighting {
- background-color: #7d7d7d4e;
+ pointer-events: none;
}
#lockTimer,
@@ -113,26 +23,20 @@
height: 0.6vh;
}
-#lockTimer::-webkit-progress-bar,
-#lockCounter::-webkit-progress-bar,
-#garbageQueue::-webkit-progress-bar {
+:is(#lockTimer, #lockCounter, #garbageQueue)::-webkit-progress-bar {
background-color: var(--invis);
}
-#lockTimer::-moz-progress-bar,
-#lockCounter::-moz-progress-bar,
-#garbageQueue::-moz-progress-bar {
+:is(#lockTimer, #lockCounter, #garbageQueue)::-moz-progress-bar {
background-color: var(--invis);
}
-#lockTimer::-webkit-progress-value,
-#lockCounter::-webkit-progress-value {
+:is(#lockTimer, #lockCounter)::-webkit-progress-value {
background-color: var(--cl-blue);
border-radius: 0.7vh;
}
-#lockTimer::-moz-progress-value,
-#lockCounter::-moz-progress-value {
+:is(#lockTimer, #lockCounter)::-moz-progress-value {
background-color: var(--cl-blue);
border-radius: 0.7vh;
}
@@ -160,123 +64,6 @@
border-radius: 0.7vh;
}
-#timeLeftText {
- font-family: "Montserrat", sans-serif;
- font-weight: bold;
- color: gold;
- font-size: 1em;
- width: 100%;
- text-align: center;
- bottom: 75%;
- opacity: 0;
- transition: all 0.3s ease;
-}
-
-#timeLeftText.warn {
- animation: timeLeft 3s;
-}
-
-@keyframes timeLeft {
- 0% {
- opacity: 1;
- letter-spacing: 0px;
- color: gold;
- }
-
- 5%{
- color: red;
- }
-
- 10%{
- color: gold;
-
- }
-
- 15%{
- color: red;
- }
-
- 20%{
- color: gold;
-
- }
-
- 25%{
- color: red;
- }
-
- 30%{
- color: gold;
-
- }
-
- 35%{
- color: red;
- }
-
- 40%{
- color: gold;
-
- }
-
- 45%{
- color: red;
- }
-
- 50%{
- color: gold;
-
- }
-
- 55%{
- color: red;
- }
-
- 60%{
- color: gold;
-
- }
-
- 65%{
- color: red;
- }
-
- 70% {
- opacity: 1;
- color:gold
- }
-
- 75%{
- color: red;
- }
-
- 80%{
- color: gold;
-
- }
-
- 85%{
- color: red;
- }
-
- 90%{
- color: gold;
-
- }
-
- 95%{
- color: red;
- }
-
-
- 100% {
- opacity: 0;
- letter-spacing: 5px;
- color: gold;
- }
-}
-
-
#garbageQueue {
position: absolute;
width: 122vh;
@@ -332,19 +119,19 @@
}
}
-.objectiveText {
- left: 110%;
- bottom: 10%;
-}
-
#redochoices {
position: absolute;
- top: 100%;
- left: 110%;
- width: 40vw;
+ display: flex;
+ bottom: 8vh;
+ width: 100%;
+ flex-direction: row;
+ text-align: center;
+ justify-content: center;
+ align-items: center;
+ flex-wrap: wrap;
opacity: 0;
- pointer-events: none;
transition: all 0.3s ease;
+ user-select: none;
}
.redochoice {
diff --git a/styles/menus.css b/styles/menus.css
index b03a189..49f6a61 100644
--- a/styles/menus.css
+++ b/styles/menus.css
@@ -270,21 +270,7 @@ button>img {
text-shadow: 0 0 3vh white;
}
-/* stats */
-.smalltext {
- position: absolute;
- font-size: 0.9em;
- color: var(--l-gray);
- user-select: none;
-}
-
-#explanationText,
-#updatetext {
- display: flex;
- margin: 0;
- opacity: 0.4;
-}
-
+/* do not remove, used in menu */
.statText {
opacity: 1;
display: flex;
@@ -313,4 +299,11 @@ button>img {
display: block;
color: #fff;
font-size: .6em;
+}
+
+#explanationText,
+#updatetext {
+ display: flex;
+ margin: 0;
+ opacity: 0.4;
}
\ No newline at end of file
diff --git a/styles/style.css b/styles/style.css
index 8dce86e..815b7b5 100644
--- a/styles/style.css
+++ b/styles/style.css
@@ -1,4 +1,3 @@
-@import url("https://fonts.googleapis.com/css2?family=Montserrat&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Major+Mono+Display&display=swap");
:root {
From 0e8e3e48376299ddc7487183697320523cb02073 Mon Sep 17 00:00:00 2001
From: TitanPlayz <118145727+TitanPlayz100@users.noreply.github.com>
Date: Tue, 29 Oct 2024 23:12:49 +1100
Subject: [PATCH 5/6] base classic mode
---
info.md | 2 ++
src/data/gamemodes.json | 18 ++++++++++++++++++
2 files changed, 20 insertions(+)
diff --git a/info.md b/info.md
index cb5ac74..659f200 100644
--- a/info.md
+++ b/info.md
@@ -71,6 +71,8 @@ Things that I am working on based on other changes
- arcade mode
- rotation centres
+- issue holding softdrop and left/right removes piece dropping cooldown
+
- CHANGE GAME CLASS TO BE EXPORTED MODULES
- remove all this.game references in replacement with just the class being imported
- **no longer shall the shackles of past object oriented java code bound the multiparadigm eutopia which is javascript**
diff --git a/src/data/gamemodes.json b/src/data/gamemodes.json
index 418885b..81f814b 100644
--- a/src/data/gamemodes.json
+++ b/src/data/gamemodes.json
@@ -22,6 +22,7 @@
"goalStat": "",
"target": "",
"result": "",
+
"music": "",
"compmusic": "",
"startBoard": "",
@@ -143,5 +144,22 @@
"allspin": true,
"allspinminis": true
}
+ },
+ "classic": {
+ "displayName": "Classic",
+ "objectiveText": "Score",
+ "goalStat": "score",
+ "target": "clearlines",
+ "result": "score",
+ "settings": {
+ "requiredLines": 999,
+ "gravitySpeed": 999,
+ "lockDelay": 30,
+ "maxLockMovements": 1,
+ "nextPieces": 1,
+ "allowHold": false,
+ "sidebar": ["time", "score", "pps"],
+ "clearDelay": 500
+ }
}
}
\ No newline at end of file
From e01513093a33ea19a50be742244033405e2bc86c Mon Sep 17 00:00:00 2001
From: TitanPlayz <118145727+TitanPlayz100@users.noreply.github.com>
Date: Tue, 29 Oct 2024 23:30:57 +1100
Subject: [PATCH 6/6] bug fix zenith
---
src/mechanics/gamemode_extended.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/mechanics/gamemode_extended.js b/src/mechanics/gamemode_extended.js
index 251c268..0ea9167 100644
--- a/src/mechanics/gamemode_extended.js
+++ b/src/mechanics/gamemode_extended.js
@@ -109,8 +109,9 @@ export class Zenith {
climbSpeedBar.value = point
climbSpeedBar.max = require
- document.styleSheets[1].cssRules[24].style.backgroundColor = color[speed - 1]
- document.styleSheets[1].cssRules[23].style.backgroundColor = color[speed]
+ // changes css variable, better selection
+ document.getElementById("climbSpeedBar").style.setProperty("--background-colour", color[speed-1])
+ document.getElementById("climbSpeedBar").style.setProperty("--bar-colour", color[speed])
}
}