[READ-ONLY] Mirror of https://github.com/flo-bit/shadow-shmup. Fun and casual top-down, roguelike shoot 'em up browsergame with shadow elements and colorful neon effects flo-bit.dev/shadow-shmup/
browsergame pixijs rapier2d roguelike shoot-em-up typescript webgame
0

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #16 from flo-bit/main

Pr

authored by

Florian and committed by
GitHub
(Aug 7, 2024, 7:36 PM +0200) 9426fdec 563c28da

+138 -34
+5 -1
Readme.md
··· 6 6 7 7 WIP. See the current development version on [GitHub Pages](https://flo-bit.github.io/shadow-shmup/). 8 8 9 + 10 + https://github.com/user-attachments/assets/25994b9d-67f5-4e80-a42a-bcd9d6999a5b 11 + 12 + 9 13 ## How to play 10 14 11 15 - Move with WASD or arrow keys ··· 141 145 142 146 - [ ] sometimes stuck in wall (moving when low fps or spawn in wall) 143 147 - [ ] weapons still active after player death (in coop) 144 - - [ ] bloom sometimes doesn't work (line enemy?) 148 + - [ ] bloom sometimes doesn't work (line enemy?)
+2 -2
index.html
··· 2 2 <html lang="en" class="m-0 overflow-hidden overscroll-none select-none"> 3 3 <head> 4 4 <meta charset="UTF-8" /> 5 - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 5 + <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" /> 6 6 <meta name="apple-mobile-web-app-capable" content="yes" /> 7 7 <meta name="apple-mobile-web-app-status-bar-style" content="black" /> 8 8 <meta name="apple-mobile-web-app-title" content="shadow shooter" /> ··· 16 16 17 17 <link rel="stylesheet" href="./index.css" /> 18 18 </head> 19 - <body class="m-0 bg-black overflow-hidden overscroll-none select-none"> 19 + <body class="m-0 bg-black overflow-hidden overscroll-none select-none touch-none"> 20 20 <script src="src/app.ts" type="module"></script> 21 21 22 22 <div id="counter" class="absolute top-1 right-1 text-white font-bold"></div>
+28 -8
src/enemies/enemy.ts
··· 19 19 20 20 enemyContainer: PIXI.Container; 21 21 22 - health: number; 23 - maxHealth: number; 22 + health: number = 0; 23 + maxHealth: number = 0; 24 24 25 25 healthBar?: PIXI.Graphics; 26 26 ··· 51 51 52 52 value: number = 1; 53 53 54 + eyeScale: number = 1; 55 + 56 + eyeDistance: number = 0.5; 57 + 54 58 hitPlayer?(player: Player): void; 55 59 56 60 constructor(game: Game) { ··· 65 69 66 70 game.container.addChild(this.enemyContainer); 67 71 68 - this.maxHealth = 30; 69 - this.health = this.maxHealth; 70 - 71 72 this.exploding = false; 72 73 this.destroyTime = -1; 73 74 ··· 75 76 76 77 this.isEnemy = true; 77 78 78 - if (game.debug) this.createHealthBar(); 79 + this.setStats(); 80 + } 81 + 82 + setStats() { 83 + this.maxHealth = 30; 84 + this.health = this.maxHealth; 79 85 } 80 86 81 87 setup() { 82 88 this.createShape(); 83 89 this.createRidigBody(); 84 90 this.createEyes(); 91 + 92 + if (this.game.debug) this.createHealthBar(); 85 93 } 86 94 87 95 setPositionNearPlayer() { ··· 103 111 this.eyes = new PIXI.Container(); 104 112 this.enemyContainer.addChild(this.eyes); 105 113 106 - this.leftEye = new Eye(this.eyes, -this.size / 4, 0, this.color); 107 - this.rightEye = new Eye(this.eyes, this.size / 4, 0, this.color); 114 + this.leftEye = new Eye( 115 + this.eyes, 116 + -this.size * this.eyeDistance * 0.5, 117 + 0, 118 + this.color, 119 + this.eyeScale 120 + ); 121 + this.rightEye = new Eye( 122 + this.eyes, 123 + this.size * this.eyeDistance * 0.5, 124 + 0, 125 + this.color, 126 + this.eyeScale 127 + ); 108 128 } 109 129 110 130 createShape() {
+85 -16
src/enemies/triangle-enemies.ts
··· 8 8 import Player from '../player/player'; 9 9 10 10 export class TriangleEnemy extends Enemy { 11 - projectile: Projectile; 12 - 13 - color = 0x0ea5e9; 11 + projectile?: Projectile; 14 12 15 13 constructor(game: Game) { 16 14 super(game); 17 15 18 - this.type = 0; 19 - this.speed = 600; 16 + this.setup(); 17 + } 20 18 19 + setStats(): void { 20 + this.health = 50; 21 + 22 + this.color = 0x0ea5e9; 23 + this.type = 0; 24 + this.speed = 1000; 25 + this.size = 25; 26 + } 27 + 28 + setup(): void { 29 + super.setup(); 30 + 31 + this.createWeapon(); 32 + } 33 + 34 + createWeapon(): void { 21 35 let position = { x: this.x, y: this.y }; 22 36 23 37 this.projectile = new Projectile(this.game, { ··· 33 47 collisionGroups: 0x00100001, 34 48 color: this.color 35 49 }); 36 - 37 - this.setup(); 38 - } 39 - 40 - createEyes() { 41 - super.createEyes(); 42 50 } 43 51 44 52 createShape(): void { 45 - this.size = 20; 46 53 this.shape = new PIXI.Graphics() 47 54 .poly([-this.size, -this.size / 2, this.size, -this.size / 2, 0, this.size]) 48 55 .fill(0); ··· 108 115 const x = Math.cos(this.rotation + Math.PI / 2); 109 116 const y = Math.sin(this.rotation + Math.PI / 2); 110 117 111 - this.projectile.setPosition(this.x + x * 20 - 1, this.y + y * 20 - 1); 118 + this.projectile?.setPosition(this.x + x * this.size - 1, this.y + y * this.size - 1); 112 119 113 - if (distance < nearestPlayer.viewDistance) { 120 + if (distance < nearestPlayer.viewDistance && this.projectile) { 114 121 this.projectile.shape.alpha = 1; 115 - } else { 122 + } else if (this.projectile) { 116 123 this.projectile.shape.alpha = 0; 117 124 } 118 125 } ··· 120 127 destroy(dropItem: boolean = true): void { 121 128 if (this.destroyed) return; 122 129 123 - this.projectile.destroy(); 130 + this.projectile?.destroy(); 124 131 super.destroy(dropItem); 132 + } 133 + } 134 + 135 + export class SmallTriangleEnemy extends TriangleEnemy { 136 + setStats(): void { 137 + this.health = 10; 138 + 139 + this.type = 0; 140 + this.speed = 900; 141 + this.size = 15; 142 + 143 + this.color = 0x06b6d4; 144 + 145 + this.eyeScale = 0.7; 146 + } 147 + 148 + createShape(): void { 149 + this.shape = new PIXI.Graphics() 150 + .poly([-this.size, -this.size, this.size, -this.size, 0, this.size]) 151 + .fill(0); 152 + this.enemyContainer.addChild(this.shape); 153 + 154 + this.highlight = new PIXI.Graphics() 155 + .poly([-this.size, -this.size, this.size, -this.size, 0, this.size]) 156 + .fill(this.color); 157 + 158 + this.enemyContainer.addChild(this.highlight); 159 + this.highlight.alpha = 0; 160 + } 161 + 162 + createRidigBody(): void { 163 + const rigidBodyDesc = RAPIER() 164 + .RigidBodyDesc.dynamic() 165 + .setTranslation(this.x, this.y) 166 + .setLinearDamping(1); 167 + this.rigidBody = this.game.world.createRigidBody(rigidBodyDesc); 168 + 169 + const colliderDesc = RAPIER() 170 + .ColliderDesc.triangle( 171 + new Vector2(-this.size, this.size), 172 + new Vector2(this.size, this.size), 173 + new Vector2(0, -this.size) 174 + ) 175 + .setActiveEvents(RAPIER().ActiveEvents.COLLISION_EVENTS) 176 + .setCollisionGroups(0x00020007) 177 + .setDensity(1); 178 + 179 + this.game.world.createCollider(colliderDesc, this.rigidBody); 180 + 181 + this.rigidBody.userData = this; 182 + } 183 + } 184 + 185 + export class BigTriangleEnemy extends TriangleEnemy { 186 + setStats(): void { 187 + this.health = 100; 188 + 189 + this.type = 0; 190 + this.speed = 2000; 191 + this.size = 40; 192 + this.color = 0x3b82f6; 193 + this.eyeScale = 1.5; 125 194 } 126 195 }
+3 -2
src/player/player.ts
··· 63 63 64 64 this.size = 25; 65 65 66 - this._maxHealth = 100; 66 + this._maxHealth = 200; 67 67 this._health = this._maxHealth; 68 68 69 69 this.color = num === 0 ? 0xbe123c : 0xf97316; ··· 91 91 color: this.color, 92 92 lifetime: 2000, 93 93 piercing: 1, 94 - fireRate: 800 94 + fireRate: 300, 95 + damage: 20 95 96 }); 96 97 97 98 this.isPlayer = true;
+15 -5
src/visuals/eye.ts
··· 20 20 21 21 color: number; 22 22 23 - constructor(container: PIXI.Container, shiftX: number, shiftY: number, color = 0xffffff) { 23 + scale: number = 1; 24 + 25 + constructor( 26 + container: PIXI.Container, 27 + shiftX: number, 28 + shiftY: number, 29 + color = 0xffffff, 30 + scale: number = 1 31 + ) { 24 32 this.eyeContainer = new PIXI.Container(); 25 33 26 34 this.eyeContainer.position.set(shiftX, shiftY); 35 + 36 + this.scale = scale; 27 37 28 38 container.addChild(this.eyeContainer); 29 39 ··· 32 42 } 33 43 34 44 async loadLayers() { 35 - const base = new PIXI.Graphics().ellipse(0, 0, 5, 4).fill(this.color); //.fill(0xe11d48); 45 + const base = new PIXI.Graphics().ellipse(0, 0, 5 * this.scale, 4 * this.scale).fill(this.color); //.fill(0xe11d48); 36 46 this.base = base; 37 47 this.base.alpha = 0; 38 48 this.eyeContainer.addChild(base); 39 49 40 - const pupil = new PIXI.Graphics().circle(0, 0, 3).fill(0x000000); 50 + const pupil = new PIXI.Graphics().circle(0, 0, 3 * this.scale).fill(0x000000); 41 51 this.pupil = pupil; 42 52 this.eyeContainer.addChild(pupil); 43 53 44 - const mask = new PIXI.Graphics().ellipse(0, 0, 5, 4).fill(0xffffff); 54 + const mask = new PIXI.Graphics().ellipse(0, 0, 5 * this.scale, 4 * this.scale).fill(0xffffff); 45 55 this.mask = mask; 46 56 this.eyeContainer.addChild(mask); 47 57 ··· 55 65 this.dx = this.dx * 0.9 + newDx * 0.1; 56 66 this.dy = this.dy * 0.9 + newDy * 0.1; 57 67 58 - this.pupil?.position.set(this.dx * 2, this.dy * 2); 68 + this.pupil?.position.set(this.dx * 2 * this.scale, this.dy * 2 * this.scale); 59 69 } 60 70 61 71 update(deltaTime: number, alpha: number) {