Graphics change, more light thanks to optimized computations

This commit is contained in:
Renan LE CARO 2025-04-03 15:15:00 +02:00
parent 83c79b6564
commit ba7e368938
16 changed files with 215 additions and 90 deletions

View file

@ -19,6 +19,11 @@ Break colourful bricks, catch bouncing coins and select powerful upgrades !
## Next release
- Abandoned : WebGl rendering of the lights in the background is too complex, first results unconvincing
- Graphics : option to make coins pretty vs readable
- Graphics : much more light thanks to faster computations
- Graphics : background effects are not computed on a much smaller resolution, and then stretched out to the full res
- Graphics : all levels background have been checked (4 buggy ones removed) and will be asigned randomly
- Fixed : display gained combo was showing +0 sometimes
## 29060272

View file

@ -29,8 +29,8 @@ android {
applicationId = "me.lecaro.breakout"
minSdk = 21
targetSdk = 34
versionCode = 29060283
versionName = "29060283"
versionCode = 29061433
versionName = "29061433"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true

85
dist/index.html vendored

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
// The version of the cache.
const VERSION = "29060283";
const VERSION = "29061433";
// The name of the cache
const CACHE_NAME = `breakout-71-${VERSION}`;

View file

@ -13,15 +13,8 @@
"<svg xmlns='http://www.w3.org/2000/svg' width='40' height='59.428'><path d='M0 70.975V47.881m20-1.692L8.535 52.808v13.239L20 72.667l11.465-6.62V52.808zm0-32.95l11.465-6.62V-6.619L20-13.24 8.535-6.619V6.619L20 13.24m8.535 4.927v13.238L40 38.024l11.465-6.62V18.166L40 11.546zM20 36.333L0 47.88m0 0v23.094m0 0l20 11.548 20-11.548V47.88m0 0L20 36.333m0 0l20 11.549M0 11.547l-11.465 6.619v13.239L0 38.025l11.465-6.62v-13.24L0 11.548v-23.094l20-11.547 20 11.547v23.094M20 36.333V13.24' stroke-width='1' stroke='white' fill='none'/></svg>",
"<svg xmlns='http://www.w3.org/2000/svg' width='70' height='8'><path d='M-.02 22c8.373 0 11.938-4.695 16.32-9.662C20.785 7.258 25.728 2 35 2c9.272 0 14.215 5.258 18.7 10.338C58.082 17.305 61.647 22 70.02 22M-.02 14.002C8.353 14 11.918 9.306 16.3 4.339 20.785-.742 25.728-6 35-6 44.272-6 49.215-.742 53.7 4.339c4.382 4.967 7.947 9.661 16.32 9.664M70 6.004c-8.373-.001-11.918-4.698-16.3-9.665C49.215-8.742 44.272-14 35-14c-9.272 0-14.215 5.258-18.7 10.339C11.918 1.306 8.353 6-.02 6.002' stroke-width='1' stroke='white' fill='none'/></svg>",
"<svg xmlns='http://www.w3.org/2000/svg' width='45' height='51.96'><path d='M52.48 44.47a15 15 0 01-14.96 0 15 15 0 00-7.48 12.96M7.48 44.42a15 15 0 01-14.96 0M15 57.44c0-5.35-2.9-10.35-7.52-13.02a15 15 0 017.48-12.97M7.48 18.5a14.97 14.97 0 01-14.98-.03m15.02-.03A15 15 0 0115 5.47a15 15 0 00-4.4-10.62m23.8.05A15 15 0 0030 5.53a15 15 0 017.48 12.96 14.9 14.9 0 0015.02-.03m-22.5 13a15.13 15.13 0 017.52 13.01m-7.56-39a15 15 0 01-14.96 0M7.48 18.5a15 15 0 017.48 12.96 15 15 0 0015.04 0 15 15 0 017.48-12.96' stroke-width='1' stroke='white' fill='none'/></svg>",
"<svg xmlns=\"http://www.w3.org/2000/svg\" xml:space=\"preserve\" width=\"45.491\" height=\"44.293\" viewBox=\"0 0 12.036 11.719\"><path d=\"M-.036-.081h12.157V11.82H-.036z\" style=\"fill:#000;stroke:none;stroke-width:.112189;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill;stop-color:#000\"/><path d=\"M.051.134h3.622v3.615h3.981V7.55h4.13v4.006\" style=\"fill:none;stroke:#fff;stroke-width:.307996;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;-inkscape-stroke:none;paint-order:markers stroke fill;stop-color:#000\"/></svg>",
"<svg xmlns='http://www.w3.org/2000/svg' width='72' height='43.875'><path d='m14.296 7.185 7.236 7.234L36.002-.048l14.47 14.47 7.236-7.233L36-14.518Zm-7.275 7.251 7.258 7.26 7.259-7.26-7.258-7.259zm-28.798 14.76 7.237 7.237L-.023 21.916 14.452 36.39l7.26-7.258L0 7.42Zm50.746 7.193-7.258-7.258-7.26 7.258 7.26 7.26zm57.568.046 7.24-7.238L72 7.42 50.282 29.137l7.259 7.259L72.02 21.918Zm-28.993-.042-7.26-7.258-7.258 7.258 7.26 7.26zm.233 14.742L36 29.358 14.223 51.135l7.258 7.258L36 43.875l14.518 14.517ZM50.453 14.45l7.259 7.26 7.258-7.26-7.258-7.257z' stroke-width='1' stroke='white' fill='none'/></svg>",
"<svg xmlns=\"http://www.w3.org/2000/svg\" xml:space=\"preserve\" width=\"88.718\" height=\"59.048\" viewBox=\"0 0 23.473 15.623\"><path d=\"M-.036-.081h23.591v15.862H-.036z\" style=\"fill:#000;stroke:none;stroke-width:.180422;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill;stop-color:#000\"/><path d=\"M-1.054 7.864h26.127M-1.185 15.474h26.128M11.545 7.765V-2.431M4.444 8.028v7.389M17.637 8.06v7.39\" style=\"fill:#fff;stroke:#fff;stroke-width:.307996;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;-inkscape-stroke:none;paint-order:markers stroke fill;stop-color:#000\"/></svg>",
"<svg xmlns=\"http://www.w3.org/2000/svg\" xml:space=\"preserve\" width=\"45.491\" height=\"44.293\" viewBox=\"0 0 12.036 11.719\"><path d=\"M-.036-.081h12.157V11.82H-.036z\" style=\"fill:#000;stroke:none;stroke-width:.112189;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill;stop-color:#000\"/><path d=\"M5.997 9.079c1.941-1.892 5.045-5.609 3.495-6.38-1.43-.71-2.665.599-3.317 1.603-.521-.96-1.47-2.616-2.839-1.655-1.898 1.334.838 5.026 2.661 6.432\" style=\"fill:none;stroke:#fff;stroke-width:.307996;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;-inkscape-stroke:none;paint-order:markers stroke fill;stop-color:#000\"/></svg>",
"<svg xmlns='http://www.w3.org/2000/svg' width='40' height='40'><path d='M27.26 5.415c-.55 0-.9.55-.65 1l2.45 4.75c.2.5.85.5 1.15.1l3.15-4.5c.3-.4 0-1.05-.55-1.1zM10.689 8.068c-.406-.051-.822.31-.778.748l.5 5.3c.05.5.6.8 1.05.5l4.55-3.05c.45-.3.4-.95-.05-1.15l-5.1-2.3a.605.605 0 0 0-.172-.048zM2.406 24.584a.635.635 0 0 0-.345.081l-4.75 2.4c-.45.2-.5.85-.1 1.15l4.45 3.15c.4.3 1 0 1.1-.5l.3-5.55c0-.412-.31-.712-.655-.73zm40 0a.635.635 0 0 0-.345.081l-4.75 2.4c-.45.2-.5.85-.1 1.15l4.45 3.15c.4.3 1 0 1.1-.5l.3-5.55c0-.412-.31-.712-.655-.73zm-22.17 3.108a.744.744 0 0 0-.675.723l.4 5.55c.05.5.6.8 1.05.5l4.45-2.95c.45-.25.4-.9-.05-1.15l-4.8-2.6a.702.702 0 0 0-.376-.073z' stroke='none' fill='white'/></svg>",
"<svg xmlns=\"http://www.w3.org/2000/svg\" xml:space=\"preserve\" width=\"45.701\" height=\"36.148\" viewBox=\"0 0 12.092 9.564\"><path d=\"M-.036-.081h12.157V11.82H-.036z\" style=\"fill:#000;stroke:none;stroke-width:.112189;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill;stop-color:#000\" transform=\"translate(0 -.76)\"/><path d=\"M.049 2.794c2.088-1.328 4.06-1.436 5.864-.036 1.804 1.401 5.21.78 6.074.013M.157 5.687C2.245 4.359 4.217 4.25 6.02 5.65c1.803 1.401 5.21.78 6.074.013M.137 8.792C2.225 7.465 4.197 7.356 6 8.757s5.21.779 6.074.013\" style=\"fill:none;stroke:#fff;stroke-width:.307999;stroke-linecap:square;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000\" transform=\"translate(0 -.76)\"/></svg>",
"<svg xmlns='http://www.w3.org/2000/svg' width='40' height='40'><path d='M45.69 13.342c-1.677.945-3.557 1.6-5.48 1.588-1.922-.012-3.795-.691-5.462-1.653-1.668-.962-3.156-2.202-4.637-3.435-1.48-1.232-2.97-2.47-4.641-3.427-1.67-.957-3.547-1.628-5.47-1.628-1.923 0-3.8.67-5.47 1.628-1.67.956-3.161 2.195-4.641 3.427-1.48 1.233-2.97 2.473-4.637 3.435-1.667.962-3.54 1.641-5.463 1.653-1.922.012-3.802-.643-5.478-1.588v13.316c1.676-.945 3.556-1.6 5.478-1.588 1.923.012 3.796.691 5.463 1.653 1.668.962 3.156 2.202 4.637 3.435 1.48 1.232 2.97 2.47 4.641 3.427 1.67.957 3.547 1.628 5.47 1.628 1.923 0 3.8-.67 5.47-1.628 1.67-.956 3.161-2.195 4.641-3.427 1.48-1.233 2.97-2.473 4.637-3.435 1.667-.962 3.54-1.641 5.463-1.653 1.922-.012 3.802.643 5.478 1.588z' stroke-width='1' stroke='white' fill='none'/></svg>",
"<svg xmlns=\"http://www.w3.org/2000/svg\" xml:space=\"preserve\" width=\"45.491\" height=\"44.293\" viewBox=\"0 0 12.036 11.719\"><path d=\"M-.036-.081h12.157V11.82H-.036z\" style=\"fill:#000;stroke:none;stroke-width:.112189;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill;stop-color:#000\"/><path d=\"M.058.132h6.413V6.34H2.006v4.024h8.68v-8.96H8.303v7.292H3.979\" style=\"fill:none;stroke:#fff;stroke-width:.307996;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;-inkscape-stroke:none;paint-order:markers stroke fill;stop-color:#000\"/><path d=\"M3.73 3.095H.034v8.58\" style=\"fill:none;stroke:#fff;stroke-width:.307996;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;-inkscape-stroke:none;paint-order:markers stroke fill;stop-color:#000\"/></svg>",
"<svg xmlns=\"http://www.w3.org/2000/svg\" xml:space=\"preserve\" width=\"88.718\" height=\"59.048\" viewBox=\"0 0 23.473 15.623\"><path d=\"M-.036-.081h23.591v15.862H-.036z\" style=\"fill:#000;stroke:none;stroke-width:.180422;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill;stop-color:#000\"/><path d=\"m23.463 8.674.044-8.608L11.47 6.941-.06.166\" style=\"fill:none;stroke:#fff;stroke-width:.307996;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;-inkscape-stroke:none;paint-order:markers stroke fill;stop-color:#000\"/><path d=\"M11.472 6.937v8.574l11.943-6.896M11.507 15.438-.024 8.78\" style=\"fill:none;stroke:#fff;stroke-width:.307996;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;-inkscape-stroke:none;paint-order:markers stroke fill;stop-color:#000\"/></svg>",
"<svg xmlns='http://www.w3.org/2000/svg' width='20' height='40'><path d='M0 0v5.436c.385-.146.767.123 1.163.82.948 1.674 2.214 2.996 3.46 4.294C6.977 13.002 9.2 15.318 9.2 19.995c0 4.679-2.223 6.994-4.577 9.447-1.246 1.299-2.512 2.621-3.46 4.295-.396.698-.777.966-1.163.82V40h1.198v-.005c0-4.678 2.224-6.992 4.579-9.445 1.245-1.298 2.51-2.62 3.459-4.295.654-1.154 1.273-1.154 1.926 0 .95 1.673 2.214 2.997 3.46 4.295 2.353 2.452 4.578 4.767 4.578 9.445V40h.8v-5.442c-.252-.095-.504-.365-.762-.82-.95-1.675-2.214-2.998-3.46-4.296-2.353-2.452-4.576-4.768-4.576-9.447-.001-4.678 2.221-6.993 4.575-9.445 1.246-1.298 2.512-2.62 3.46-4.294.259-.456.511-.725.763-.82V0h-.8c0 4.676-2.224 6.991-4.577 9.442-1.246 1.298-2.512 2.621-3.46 4.296-.653 1.153-1.273 1.153-1.926 0-.948-1.675-2.214-2.998-3.46-4.296C3.424 6.991 1.2 4.676 1.2 0Z' stroke='none' fill='white'/></svg>",
"<svg xmlns='http://www.w3.org/2000/svg' width='50' height='33.333'><path d='M25 .806v2.79h.8V.806Zm0 4.465v2.791h.8v-2.79Zm-2.043 3.902-2.32 1.55.444.665 2.32-1.55-.443-.665zm4.885 0-.444.665 2.32 1.55.445-.665zM-.4 10.61v2.79h.8v-2.79zm50 0v2.79h.8v-2.79zm-30.356 1.042-2.32 1.55.443.666 2.322-1.55-.444-.666zm12.311 0-.444.665 2.32 1.55.445-.664zm3.783 2.566-.444.666 2.321 1.55.444-.666zm-19.852.025-2.32 1.55.444.665 2.32-1.55zm-15.886.77v2.79h.8v-2.79Zm50 0v2.79h.8v-2.79Zm-50 4.465v2.79h.8v-2.79h-.8Zm50 0v2.79h.8v-2.79h-.8zM2.442 23.379l-.444.665 2.32 1.55.445-.665zm45.115 0-2.32 1.55.443.666 2.322-1.55-.444-.666zM6.155 25.86l-.444.665 2.32 1.55.445-.665zm37.69 0-2.322 1.55.444.665 2.321-1.55-.444-.666zM9.937 28.424l-.444.665 2.32 1.55.445-.665-2.321-1.55zm30.11.003-2.321 1.55.444.666 2.321-1.55zM25 29.737v2.79h.8v-2.79z' stroke='none' fill='white'/></svg>",
"<svg xmlns='http://www.w3.org/2000/svg' width='69.282' height='40'><path d='M34.641-20v80m34.64-40L0-20m69.282 80L0 20m69.282 0L0 60m69.282-80L0 20m69.282-40v80M0-20v80M34.64 40l11.547-20m11.547 20l11.547 20M34.641 40h23.094m11.547-20L57.735 40M46.188 20L34.641 40l11.547 20h23.094L80.83 40 69.282 20H46.188zM34.641 40l11.547-20m11.547 20l11.547 20M34.641 40h23.094m11.547-20L57.735 40M46.188 20L34.641 40l11.547 20h23.094L80.83 40 69.282 20H46.188zM34.641 0l11.547-20M57.735 0l11.547 20M34.642 0h23.093m11.547-20L57.735 0M46.188-20L34.641 0l11.547 20h23.094L80.83 0 69.282-20H46.188zM34.641 40L23.094 20M11.547 40L0 60m34.64-20H11.548M0 20l11.547 20m11.547-20l11.547 20-11.547 20H0l-11.547-20L0 20h23.094zM34.641 0L23.094-20M11.547 0L0 20M34.64 0H11.548M0-20L11.547 0m11.547-20L34.641 0 23.094 20H0L-11.547 0 0-20h23.094z' stroke-width='1' stroke='white' fill='none'/></svg>",

View file

@ -3,27 +3,28 @@
"name": "71 mini",
"size": 5,
"bricks": "bbb____bt__btt__b_t___ttt",
"svg": 23,
"svg": 1,
"color": ""
},
{
"name": "Butterfly",
"bricks": "_________bb_t_t_bbbbb_t_bbbbbbbtbbbb_bbbtbbb____btb____bbbtbbb__bb_t_bb__________",
"size": 9,
"svg": 20,
"svg": 2,
"color": ""
},
{
"name": "Castle",
"size": 7,
"bricks": "s_s_s_ssssssssssBBBssssBBBssttbbbttttbbbtttbtbtbt",
"svg": 16
"svg": 3,
"color": ""
},
{
"name": "Eyes",
"size": 9,
"bricks": "ttttttt__tWWWWWWW_tWrrWttW_tWWWWWWW_ttttttt_____t______ttttt____ttttt_____t_t",
"svg": null,
"svg": 4,
"color": "",
"credit": "https://steamcommunity.com/sharedfiles/filedetails/?id=487035876"
},
@ -31,21 +32,23 @@
"name": "Creeper",
"size": 10,
"bricks": "___________ccGGccGG__cGccGcGc__GBBccBBc__cBBGcBBc__GccBBGGc__ccBBBBcG__GGBBBBcG__cGBccBGc___________",
"svg": 22,
"credit": "https://en.wikipedia.org/wiki/Creeper_(Minecraft)"
"svg": 5,
"credit": "https://en.wikipedia.org/wiki/Creeper_(Minecraft)",
"color": ""
},
{
"name": "Stairs",
"size": 8,
"bricks": "tt______tt______bbtt____bbtt____vvbbtt__vvbbtt__ppvvbbttppvvbbtt",
"svg": 18,
"svg": 6,
"color": ""
},
{
"name": "Dots",
"size": 9,
"bricks": "b_t_a_c_c__________b_t_a_c__________P_b_t_a_c__________P_b_t_a__________P_P_b_t_a",
"svg": null
"svg": 7,
"color": ""
},
{
"name": "Lines",
@ -260,7 +263,7 @@
"name": "Rose",
"size": 9,
"bricks": "__SS______SSSS_____SSSS_____SSSS______SS_k______k_kk_____kk_k______kk________k",
"svg": 4,
"svg": 17,
"color": ""
},
{
@ -1086,8 +1089,8 @@
},
{
"name": "Dog 8",
"size": 16,
"bricks": "__gg_ggggg_gg___ggWWgWWWWWgWWgg_gWWgWWWWWWWgWWg_gWWgWWWWWWWgWWg_gggWWWWWWWWWggg__gWggWWWWWggWg___gWggWWWWWggWg___gWWWWgggWWWWg____gWgWWgWWgWg_____gWWggsggWWg______gWgsssgWg________ggsssgg___________ggg_______________________________________________________",
"size": 17,
"bricks": "_____________________________________gg_ggggg_gg____ggWWgWWWWWgWWgg__gWWgWWWWWWWgWWg__gWWgWWWWWWWgWWg__gggWWWWWWWWWggg___gWggWWWWWggWg____gWggWWWWWggWg____gWWWWgggWWWWg_____gWgWWgWWgWg______gWWggsggWWg_______gWgsssgWg_________ggsssgg____________ggg_________________________________________",
"svg": null,
"color": "#62a0ea",
"credit": "https://prohama.com/dog-8-pattern/"
@ -1164,4 +1167,4 @@
"svg": null,
"color": ""
}
]
]

View file

@ -1 +1 @@
"29060283"
"29061433"

View file

@ -30,6 +30,9 @@ body {
height: calc(var(--vh, 1vh) * 100);
width: 100vw;
}
canvas:not(#game) {
display: none;
}
#score,
#menu {

View file

@ -45,6 +45,8 @@ import {
backgroundCanvas,
ctx,
gameCanvas,
haloCanvas,
haloScale,
render,
scoreDisplay,
} from "./render";
@ -127,12 +129,15 @@ export const fitSize = () => {
gameState.canvasHeight = height;
gameCanvas.width = width;
gameCanvas.height = height;
ctx.fillStyle = currentLevelInfo(gameState)?.color || "black";
ctx.globalAlpha = 1;
ctx.fillRect(0, 0, width, height);
// ctx.fillStyle = currentLevelInfo(gameState)?.color || "black";
// ctx.globalAlpha = 1;
// ctx.fillRect(0, 0, width, height);
backgroundCanvas.width = width;
backgroundCanvas.height = height;
haloCanvas.width = width / haloScale;
haloCanvas.height = height / haloScale;
gameState.gameZoneHeight = isOptionOn("mobile-mode")
? (height * 80) / 100
: height;

View file

@ -2,14 +2,8 @@ import { RawLevel } from "./types";
import _backgrounds from "./data/backgrounds.json";
const backgrounds = _backgrounds as string[];
export function getLevelBackground(level: RawLevel) {
let svg = level.svg !== null && backgrounds[level.svg % backgrounds.length];
if (!level.color && !svg) {
svg = backgrounds[hashCode(level.name) % backgrounds.length];
}
return svg;
return backgrounds[hashCode(level.name) % backgrounds.length];
}
export function hashCode(string: string) {

View file

@ -1402,6 +1402,36 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>opaque_coins</name>
<description/>
<comment/>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>opaque_coins_help</name>
<description/>
<comment/>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>pointer_lock</name>
<description/>

View file

@ -88,6 +88,8 @@
"main_menu.mobile_help": "Leaves space under the puck.",
"main_menu.normal": "New short game",
"main_menu.normal_help": "Play 7 levels with a random starting perk",
"main_menu.opaque_coins": "Opaque coins with white border",
"main_menu.opaque_coins_help": "Less pretty but more readable",
"main_menu.pointer_lock": "Mouse pointer lock",
"main_menu.pointer_lock_help": "Locks and hides the mouse cursor.",
"main_menu.record": "Record gameplay videos",

View file

@ -88,6 +88,8 @@
"main_menu.mobile_help": "Laisse un espace sous le palet.",
"main_menu.normal": "Nouvelle partie rapide",
"main_menu.normal_help": "Avec un avantage de départ aléatoire",
"main_menu.opaque_coins": "",
"main_menu.opaque_coins_help": "",
"main_menu.pointer_lock": "Verrouillage du pointeur",
"main_menu.pointer_lock_help": "Cache aussi le curseur de la souris.",
"main_menu.record": "Enregistrer des vidéos de jeu",

View file

@ -15,7 +15,7 @@ export const appVersion = _appVersion as string;
export const icons = {} as { [k: string]: string };
export const allLevels = rawLevelsList
.map((level) => {
.map((level, i) => {
const bricks = level.bricks
.split("")
.map((c) => palette[c])

View file

@ -25,6 +25,11 @@ export const options = {
name: t("main_menu.colorful_coins"),
help: t("main_menu.colorful_coins_help"),
},
opaque_coins: {
default: false,
name: t("main_menu.opaque_coins"),
help: t("main_menu.opaque_coins_help"),
},
show_fps: {
default: false,
name: t("main_menu.show_fps"),

View file

@ -21,6 +21,7 @@ export const gameCanvas = document.getElementById("game") as HTMLCanvasElement;
export const ctx = gameCanvas.getContext("2d", {
alpha: false,
}) as CanvasRenderingContext2D;
export const bombSVG = document.createElement("img");
bombSVG.src =
"data:image/svg+xml;base64," +
@ -33,6 +34,13 @@ export const background = document.createElement("img");
background.onload = () => (gameState.needsRender = true);
export const backgroundCanvas = document.createElement("canvas");
export const haloCanvas = document.createElement("canvas");
const haloCanvasCtx = haloCanvas.getContext("2d", {
alpha: false,
}) as CanvasRenderingContext2D;
export const haloScale = 4;
export function render(gameState: GameState) {
if (!gameState.readyToRender) return;
const level = currentLevelInfo(gameState);
@ -94,55 +102,98 @@ export function render(gameState: GameState) {
// Clear
if (!isOptionOn("basic") && !level.color && level.svg) {
// Without this the light trails everything
ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = 1;
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, width, height);
// ctx.globalCompositeOperation = "source-over";
// ctx.globalAlpha = 1;
// ctx.fillStyle = "#000";
// ctx.fillRect(0, 0, width, height);
ctx.globalCompositeOperation = "screen";
ctx.globalAlpha = 0.6;
haloCanvasCtx.globalCompositeOperation = "source-over";
haloCanvasCtx.globalAlpha = 1;
haloCanvasCtx.fillStyle = "#000";
haloCanvasCtx.fillRect(0, 0, width / haloScale, height / haloScale);
haloCanvasCtx.globalCompositeOperation = "screen";
haloCanvasCtx.globalAlpha = 0.6;
forEachLiveOne(gameState.coins, (coin) => {
drawFuzzyBall(ctx, coin.color, gameState.coinSize * 2, coin.x, coin.y);
haloCanvasCtx.globalAlpha = 0.9;
drawFuzzyBall(
haloCanvasCtx,
coin.color,
(gameState.coinSize * 1.5) / haloScale,
coin.x / haloScale,
coin.y / haloScale,
);
haloCanvasCtx.globalAlpha = 0.4;
drawFuzzyBall(
haloCanvasCtx,
coin.color,
(gameState.coinSize * 6) / haloScale,
coin.x / haloScale,
coin.y / haloScale,
);
});
gameState.balls.forEach((ball) => {
drawFuzzyBall(
ctx,
haloCanvasCtx,
gameState.ballsColor,
gameState.ballSize * 2,
ball.x,
ball.y,
(gameState.ballSize * 2) / haloScale,
ball.x / haloScale,
ball.y / haloScale,
);
drawFuzzyBall(
haloCanvasCtx,
gameState.ballsColor,
(gameState.ballSize * 4) / haloScale,
ball.x / haloScale,
ball.y / haloScale,
);
});
ctx.globalAlpha = 0.5;
haloCanvasCtx.globalAlpha = 0.6;
gameState.bricks.forEach((color, index) => {
if (!color) return;
const x = brickCenterX(gameState, index),
y = brickCenterY(gameState, index);
drawFuzzyBall(
ctx,
haloCanvasCtx,
color == "black" ? "#666" : color,
gameState.brickWidth,
x,
y,
(gameState.brickWidth * 2) / haloScale,
x / haloScale,
y / haloScale,
);
});
ctx.globalAlpha = 1;
forEachLiveOne(gameState.particles, (flash) => {
const { x, y, time, color, size, duration } = flash;
const elapsed = gameState.levelTime - time;
ctx.globalAlpha = Math.min(1, 2 - (elapsed / duration) * 2);
drawFuzzyBall(ctx, color, size * 3, x, y);
haloCanvasCtx.globalAlpha = Math.min(1, 2 - (elapsed / duration) * 2);
drawFuzzyBall(
haloCanvasCtx,
color,
size / haloScale,
x / haloScale,
y / haloScale,
);
drawFuzzyBall(
haloCanvasCtx,
color,
(size * 4) / haloScale,
x / haloScale,
y / haloScale,
);
});
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = "source-over";
ctx.drawImage(haloCanvas, 0, 0, width, height);
// Decides how brights the bg black parts can get
ctx.globalAlpha = 0.2;
ctx.globalCompositeOperation = "multiply";
ctx.fillStyle = "black";
ctx.fillRect(0, 0, width, height);
// ctx.globalAlpha = 0.2;
// ctx.globalCompositeOperation = "multiply";
// ctx.fillStyle = "black";
// ctx.fillRect(0, 0, width, height);
// Decides how dark the background black parts are when lit (1=black)
ctx.globalAlpha = 0.8;
ctx.globalAlpha = 0.9;
ctx.globalCompositeOperation = "multiply";
if (level.svg && background.width && background.complete) {
if (backgroundCanvas.title !== level.name) {
@ -222,7 +273,10 @@ export function render(gameState: GameState) {
// Coins
ctx.globalAlpha = 1;
forEachLiveOne(gameState.coins, (coin) => {
ctx.globalCompositeOperation = "source-over";
// ctx.globalCompositeOperation = "source-over";
ctx.globalCompositeOperation = isOptionOn("opaque_coins")
? "source-over"
: "screen";
// ctx.globalCompositeOperation =
// coin.color === "gold" || level.color ? "source-over" : "screen";
drawCoin(
@ -233,7 +287,9 @@ export function render(gameState: GameState) {
coin.y,
(hasCombo && gameState.perks.asceticism && "red") ||
(coin.color === "gold" && "gold") ||
gameState.puckColor,
isOptionOn("opaque_coins")
? gameState.puckColor
: coin.color,
coin.a,
);
});
@ -279,9 +335,7 @@ export function render(gameState: GameState) {
ctx.globalAlpha = Math.max(0, Math.min(1, 2 - (elapsed / duration) * 2));
ctx.globalCompositeOperation = "screen";
drawBall(ctx, color, size, x, y);
drawFuzzyBall(ctx, color, size, x, y);
});
if (gameState.perks.extra_life) {
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = "source-over";