[object Object]

← back to Neon Baguette Battle

Bigger, faster baguette missile + alternate 1P controls (arrows to move, Space/Cmd/Ctrl to fire)

4fcd312841a805533db920504f28e3b7f3c4ab71 · 2026-08-31 13:29:46 -0700 · Steve Abrams

- Missile: velocity 11->19, size/hitbox 22->34, 1.5x render scale, faster spin, longer trail
- Array-based control maps; 1-player P1 also drives with arrows (up=jump, down=block)
- New 'fire' action (Space, Left/Right Command, Control): launches missile if meter full, else whack
- Menu hint + README document the alternate scheme

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Files touched

Diff

commit 4fcd312841a805533db920504f28e3b7f3c4ab71
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Aug 31 13:29:46 2026 -0700

    Bigger, faster baguette missile + alternate 1P controls (arrows to move, Space/Cmd/Ctrl to fire)
    
    - Missile: velocity 11->19, size/hitbox 22->34, 1.5x render scale, faster spin, longer trail
    - Array-based control maps; 1-player P1 also drives with arrows (up=jump, down=block)
    - New 'fire' action (Space, Left/Right Command, Control): launches missile if meter full, else whack
    - Menu hint + README document the alternate scheme
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
 README.md  |  5 +++++
 index.html | 47 +++++++++++++++++++++++++++--------------------
 2 files changed, 32 insertions(+), 20 deletions(-)

diff --git a/README.md b/README.md
index 5f3583d..a6da8e9 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,11 @@ also click a card to choose P1's fighter. `Enter`/`Space` or **START FIGHT** beg
 | Pause | `P` | |
 | Mute (audio + voice) | `M` | |
 
+**1-player alternate scheme (P1):** you can also play with the **arrow keys**
+(`←`/`→` move, `↑` jump, `↓` block) and **fire** with **`Space`**, **`⌘`
+Command**, or **`Ctrl`** — fire launches the baguette missile when the meter is
+full, otherwise it does a whack. (In 2-player the arrows belong to Player 2.)
+
 ## Features
 - **Real combat**: startup/active/recovery attack frames, blocking with chip
   damage, knockback, hit-stun, a build-up special meter, and a **launched
diff --git a/index.html b/index.html
index 872a307..e7c2b4f 100644
--- a/index.html
+++ b/index.html
@@ -126,7 +126,7 @@
         </table>
       </div>
     </div>
-    <div class="tiny">Press&nbsp;<span class="key">P</span>&nbsp;to pause · <span class="key">M</span>&nbsp;mute</div>
+    <div class="tiny">1-Player also: <span class="key">←</span><span class="key">→</span> move · <span class="key">↑</span> jump · <span class="key">↓</span> block · <span class="key">Space</span>/<span class="key">⌘</span>/<span class="key">Ctrl</span> fire &nbsp;·&nbsp; <span class="key">P</span> pause · <span class="key">M</span> mute</div>
   </div>
 
   <!-- CHARACTER SELECT -->
@@ -264,8 +264,12 @@
 
   // ---------- Input ----------
   const keys = {};
-  const P1MAP = { left:'a', right:'d', jump:'w', block:'s', poke:'f', swing:'g', blast:'h' };
-  const P2MAP = { left:'arrowleft', right:'arrowright', jump:'arrowup', block:'arrowdown', poke:',', swing:'.', blast:'/' };
+  // maps are arrays so an action can have several keys. 'fire' = launch missile if meter full, else whack.
+  const P1_ATTACK = { poke:['f'], swing:['g'], blast:['h'], fire:[' ','meta','control'] };
+  const P1MAP_1P  = { left:['a','arrowleft'], right:['d','arrowright'], jump:['w','arrowup'], block:['s','arrowdown'], ...P1_ATTACK };
+  const P1MAP_2P  = { left:['a'], right:['d'], jump:['w'], block:['s'], ...P1_ATTACK };  // arrows belong to P2 in 2P
+  const P2MAP     = { left:['arrowleft'], right:['arrowright'], jump:['arrowup'], block:['arrowdown'], poke:[','], swing:['.'], blast:['/'] };
+  let   p1map     = P1MAP_1P;
   addEventListener('keydown', e => {
     const k = e.key.toLowerCase();
     if (['arrowup','arrowdown','arrowleft','arrowright',' ','/'].includes(k)) e.preventDefault();
@@ -398,19 +402,21 @@
 
     controlHuman(map){
       if (this.state==='hurt'||this.state==='ko') return;
-      const left = keys[map.left], right = keys[map.right];
+      const down = a => a && a.some(k => keys[k]);
+      const hit  = a => { if (!a) return false; let h=false; for (const k of a){ if (keys['_pressed_'+k]){ keys['_pressed_'+k]=false; h=true; } } return h; };
       const speed = this.spd;
-      const canMove = !this.attack;
-      if (canMove){
-        if (left && !right){ this.vx = -speed; this.facing = -1; }
-        else if (right && !left){ this.vx = speed; this.facing = 1; }
+      const L = down(map.left), R = down(map.right);
+      if (!this.attack){
+        if (L && !R){ this.vx = -speed; this.facing = -1; }
+        else if (R && !L){ this.vx = speed; this.facing = 1; }
       }
-      if (keys[map.block] && this.onGround && !this.attack){ this.state = 'block'; }
+      if (down(map.block) && this.onGround && !this.attack){ this.state = 'block'; }
       else if (this.state==='block'){ this.state = 'idle'; }
-      if (pressed(map.jump) && this.onGround && !this.attack){ this.vy = -16; this.onGround = false; Audio.jump(); }
-      if (pressed(map.poke))  this.startAttack('poke');
-      if (pressed(map.swing)) this.startAttack('swing');
-      if (pressed(map.blast)) this.startAttack('blast');
+      if (hit(map.jump) && this.onGround && !this.attack){ this.vy = -16; this.onGround = false; Audio.jump(); }
+      if (hit(map.poke))  this.startAttack('poke');
+      if (hit(map.swing)) this.startAttack('swing');
+      if (hit(map.blast)) this.startAttack('blast');
+      if (hit(map.fire))  this.startAttack(this.meter >= 100 ? 'blast' : 'swing');  // Space / ⌘ / Ctrl
     }
 
     controlAI(foe){
@@ -672,7 +678,7 @@
   let blasts = [], sparks = [], hazards = [], hazardTimer = 140, shake = 0;
   function spawnBlast(owner){
     blasts.push({ x: owner.x + owner.facing*owner.w*0.5, y: owner.y - owner.h*0.62,
-                  vx: owner.facing*11, r: 22, owner, life: 90, t:0, rot: 0 });
+                  vx: owner.facing*19, r: 34, owner, life: 90, t:0, rot: 0 });  // fast + big
   }
   function spawnSpark(x,y,color,n){
     for (let i=0;i<n;i++){
@@ -682,7 +688,7 @@
   }
   function updateProjectiles(f1,f2){
     for (const b of blasts){
-      b.t++; b.x += b.vx; b.rot += 0.5*Math.sign(b.vx); b.life--;
+      b.t++; b.x += b.vx; b.rot += 0.7*Math.sign(b.vx); b.life--;
       const foe = b.owner === f1 ? f2 : f1;
       const hb = foe.hurtbox();
       if (b.x+b.r > hb.x && b.x-b.r < hb.x+hb.w && b.y+b.r>hb.y && b.y-b.r<hb.y+hb.h){
@@ -700,11 +706,11 @@
       g.save();
       // motion trail
       g.fillStyle = c.glow;
-      for (let i=1;i<=4;i++){ g.globalAlpha = 0.28/i; g.beginPath(); g.arc(b.x-b.vx*i*1.5, b.y, 7-i, 0, Math.PI*2); g.fill(); }
-      // the spinning baguette missile
+      for (let i=1;i<=6;i++){ g.globalAlpha = 0.30/i; g.beginPath(); g.arc(b.x-b.vx*i*0.9, b.y, 12-i, 0, Math.PI*2); g.fill(); }
+      // the big spinning baguette missile
       g.globalAlpha = 1;
-      g.translate(b.x, b.y); g.rotate(b.rot);
-      drawBaguetteWeapon(g, -24, 0, 0, 48, true);   // centered on flight path
+      g.translate(b.x, b.y); g.rotate(b.rot); g.scale(1.5, 1.5);
+      drawBaguetteWeapon(g, -33, 0, 0, 66, true);   // centered on flight path
       g.restore();
     }
     for (const s of sparks){
@@ -1061,6 +1067,7 @@
   }
   function beginSelectedMatch(){
     if (!(p1Ready && p2Ready)) return;
+    p1map = (mode==='2p') ? P1MAP_2P : P1MAP_1P;   // 1P: P1 also gets arrows + space/⌘
     f1 = new Fighter(W*0.32,'p1', ROSTER[p1Idx], true);
     f2 = new Fighter(W*0.68,'p2', ROSTER[p2Idx], mode==='2p');
     f1.rounds=0; f2.rounds=0; roundNum=1;
@@ -1171,7 +1178,7 @@
       roundTimer += dt; roundTime = Math.max(0, 60 - roundTimer/60*60*0);  // handled below
       roundTime = Math.max(0, 60 - roundTimer/60);
       // control
-      if (f1.human) f1.controlHuman(P1MAP); else f1.controlAI(f2);
+      if (f1.human) f1.controlHuman(p1map); else f1.controlAI(f2);
       if (f2.human) f2.controlHuman(P2MAP); else f2.controlAI(f1);
       f1.update(f2); f2.update(f1);
       resolveHits(f1,f2); resolveHits(f2,f1);

← d93d9ac Redesign fighters as Frenchmen in berets wielding baguettes;  ·  back to Neon Baguette Battle  ·  Play La Marseillaise on load + cobblestone street floor stre 125754f →