Skip to content

Commit e99b0d3

Browse files
committed
sunday night
1 parent 5d73cb0 commit e99b0d3

13 files changed

Lines changed: 481 additions & 14 deletions

File tree

RAW/sprites/003a.png

489 Bytes
Loading

RAW/sprites/003b.png

479 Bytes
Loading

assets/images/autotiles.png

3.4 KB
Loading

assets/images/enemies.png

148 Bytes
Loading

assets/images/enemies.xml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<TextureAtlas imagePath="002a-sprites.png">
2+
<TextureAtlas imagePath="001b-sprites.png">
33
<!--
44
Created with ShoeBox
55
http://renderhjs.net/shoebox/
66
-->
7-
<SubTexture name="001a.png" x="18" y="15" width="11" height="13" frameX="-2" frameY="-3" frameWidth="16" frameHeight="16"/>
8-
<SubTexture name="001b.png" x="18" y="0" width="12" height="13" frameX="-2" frameY="-3" frameWidth="16" frameHeight="16"/>
7+
<SubTexture name="001a.png" x="32" y="34" width="11" height="13" frameX="-2" frameY="-3" frameWidth="16" frameHeight="16"/>
8+
<SubTexture name="001b.png" x="18" y="34" width="12" height="13" frameX="-2" frameY="-3" frameWidth="16" frameHeight="16"/>
99
<SubTexture name="002a.png" x="0" y="0" width="16" height="16" frameX="-0" frameY="-0" frameWidth="16" frameHeight="16"/>
10-
<SubTexture name="002b.png" x="0" y="18" width="16" height="15" frameX="-0" frameY="-1" frameWidth="16" frameHeight="16"/>
10+
<SubTexture name="002b.png" x="18" y="0" width="16" height="15" frameX="-0" frameY="-1" frameWidth="16" frameHeight="16"/>
11+
<SubTexture name="003a.png" x="18" y="17" width="15" height="15" frameX="-1" frameY="-1" frameWidth="16" frameHeight="16"/>
12+
<SubTexture name="003b.png" x="0" y="18" width="16" height="15" frameX="-0" frameY="-1" frameWidth="16" frameHeight="16"/>
1113
</TextureAtlas>

assets/images/hud_bulb.png

218 Bytes
Loading

assets/images/hud_film.png

318 Bytes
Loading

source/Constants.hx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,18 @@ class Constants
44
{
55
// Global tile size used throughout the game (pixels)
66
public static inline var TILE_SIZE:Int = 16;
7+
// Photo mechanic tuning
8+
public static inline var PHOTO_START_FILM:Int = 20;
9+
public static inline var PHOTO_COOLDOWN:Float = 1.0;
10+
public static inline var PHOTO_FLASH_TIME:Float = 0.12;
11+
// Small pause between the instant flash/ash and the start of the dramatic crumble
12+
public static inline var PHOTO_DISSOLVE_DELAY:Float = 0.25;
13+
// Make the dissolve dramatic: increased slightly (was 2.8)
14+
public static inline var PHOTO_DISSOLVE_DURATION:Float = 3.4;
15+
16+
// Number of rows the shader uses for the stepped dissolve (should match shader ROWS)
17+
public static inline var PHOTO_DISSOLVE_ROWS:Int = 16;
18+
19+
// How many rows are removed instantly at flash (the "ash statue" base)
20+
public static inline var PHOTO_DISSOLVE_INSTANT_ROWS:Int = 2;
721
}

source/Enemy.hx

Lines changed: 163 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
package;
22

33
import flixel.FlxG;
4+
import flixel.effects.particles.FlxEmitter;
45
import flixel.graphics.frames.FlxAtlasFrames;
6+
import flixel.tweens.FlxEase;
7+
import flixel.tweens.FlxTween;
58
import haxe.ds.StringMap;
69

710
class Enemy extends GameObject
811
{
9-
// shared frames and variant list (initialized once)
12+
public var variant:String;
1013
public static var SHARED_FRAMES:FlxAtlasFrames = null;
1114
public static var VARIANTS:Array<String> = [];
12-
// map from variant id -> array of frame names (as present in the atlas)
1315
public static var VARIANT_FRAMES:StringMap<Array<String>> = null;
1416

1517
private static function ensureFrames():Void
@@ -19,12 +21,9 @@ class Enemy extends GameObject
1921
SHARED_FRAMES = FlxAtlasFrames.fromSparrow("assets/images/enemies.png", "assets/images/enemies.xml");
2022
VARIANTS = [];
2123
VARIANT_FRAMES = new StringMap<Array<String>>();
22-
23-
// Iterate atlas frames and collect prefixes where frame names end with a single letter suffix (a,b,c...)
2424
for (f in 0...SHARED_FRAMES.numFrames)
2525
{
2626
var rawName:String = SHARED_FRAMES.getByIndex(f).name;
27-
// strip extension if present
2827
var base = rawName;
2928
var dot = base.lastIndexOf('.');
3029
if (dot >= 0)
@@ -42,12 +41,163 @@ class Enemy extends GameObject
4241
VARIANT_FRAMES.set(prefix, list);
4342
VARIANTS.push(prefix);
4443
}
45-
// store the atlas frame name (use rawName as that's what the atlas uses)
4644
list.push(rawName);
4745
}
4846
}
4947
}
5048

49+
private function spawnCrumbleParticles(count:Int):Void
50+
{
51+
try
52+
{
53+
var emitter = new FlxEmitter();
54+
// emit along the bottom of the sprite so particles "rain" down
55+
emitter.setPosition(x + 2, y + height - 2);
56+
emitter.setSize(Math.max(2, width - 4), 2);
57+
emitter.makeParticles(2, 2, 0xFF888888, count);
58+
// slightly longer lifespan for falling dust
59+
emitter.lifespan.max = 0.5;
60+
emitter.lifespan.min = 0.2;
61+
// small horizontal spread, positive Y speeds so particles fall downwards
62+
emitter.speed.start.min = -10;
63+
emitter.speed.start.max = 10;
64+
emitter.speed.end.min = 20;
65+
emitter.speed.end.max = 60;
66+
// gentle downward acceleration (gravity-like)
67+
emitter.acceleration.start.min.y = 40;
68+
emitter.acceleration.end.min.y = 120;
69+
emitter.alpha.start.min = 1.0;
70+
emitter.alpha.end.max = 0.0;
71+
emitter.start(true);
72+
try
73+
{
74+
FlxG.state.add(emitter);
75+
}
76+
catch (e:Dynamic) {}
77+
}
78+
catch (e:Dynamic) {}
79+
}
80+
81+
public function capture(byPlayer:Player):Void
82+
{
83+
if (!exists)
84+
return;
85+
velocity.set(0, 0);
86+
acceleration.set(0, 0);
87+
try
88+
{
89+
trace("Enemy.capture() start - variant=" + (variant == null ? "null" : variant));
90+
}
91+
catch (e:Dynamic) {}
92+
try
93+
{
94+
if (animation != null)
95+
{
96+
animation.stop();
97+
}
98+
}
99+
catch (e:Dynamic) {}
100+
101+
try
102+
{
103+
try
104+
{
105+
trace("Enemy.capture() creating shader");
106+
}
107+
catch (e:Dynamic) {}
108+
var sh = new shaders.PhotoDissolve();
109+
try
110+
{
111+
trace("Enemy.capture() shader created");
112+
}
113+
catch (e:Dynamic) {}
114+
sh.desat = 1.0;
115+
sh.dissolve = 0.0;
116+
this.shader = sh;
117+
try
118+
{
119+
trace("Enemy.capture() shader assigned: " + (this.shader != null));
120+
}
121+
catch (e:Dynamic) {}
122+
123+
FlxTween.tween(sh, {dissolve: 1.0}, Constants.PHOTO_DISSOLVE_DURATION, {
124+
startDelay: Constants.PHOTO_DISSOLVE_DELAY,
125+
type: FlxTweenType.ONESHOT,
126+
ease: FlxEase.quadOut,
127+
onStart: function(_)
128+
{
129+
try
130+
{
131+
trace("Enemy.capture() tween started");
132+
}
133+
catch (e:Dynamic) {}
134+
try
135+
{
136+
spawnCrumbleParticles(20);
137+
}
138+
catch (e:Dynamic) {}
139+
},
140+
onComplete: function(_)
141+
{
142+
try
143+
{
144+
trace("Enemy.capture() tween complete");
145+
}
146+
catch (e:Dynamic) {}
147+
exists = false;
148+
alive = false;
149+
if (byPlayer != null)
150+
byPlayer.captured.push(variant != null ? variant : "enemy");
151+
kill();
152+
}
153+
});
154+
}
155+
catch (e:Dynamic)
156+
{
157+
try
158+
{
159+
trace("Enemy.capture() shader failed: " + Std.string(e));
160+
}
161+
catch (e:Dynamic) {}
162+
color = 0xAAAAAA;
163+
try
164+
{
165+
if (animation != null)
166+
animation.stop();
167+
}
168+
catch (e:Dynamic) {}
169+
FlxTween.tween(this, {alpha: 0}, Constants.PHOTO_DISSOLVE_DURATION, {
170+
startDelay: Constants.PHOTO_DISSOLVE_DELAY,
171+
onStart: function(_)
172+
{
173+
try
174+
{
175+
trace("Enemy.capture() fallback tween started");
176+
}
177+
catch (e:Dynamic) {}
178+
try
179+
{
180+
spawnCrumbleParticles(24);
181+
}
182+
catch (e:Dynamic) {}
183+
},
184+
onComplete: function(_)
185+
{
186+
try
187+
{
188+
trace("Enemy.capture() fallback complete");
189+
}
190+
catch (e:Dynamic) {}
191+
exists = false;
192+
alive = false;
193+
if (byPlayer != null)
194+
byPlayer.captured.push(variant != null ? variant : "enemy");
195+
kill();
196+
}
197+
});
198+
}
199+
}
200+
51201
public static function pickVariant():String
52202
{
53203
ensureFrames();
@@ -64,6 +214,10 @@ class Enemy extends GameObject
64214
public function new(tileX:Int, tileY:Int, ?variant:String)
65215
{
66216
super(tileX, tileY);
217+
if (variant == null)
218+
this.variant = pickVariant();
219+
else
220+
this.variant = variant;
67221
speed = 50;
68222
}
69223

@@ -73,7 +227,9 @@ class Enemy extends GameObject
73227
if (SHARED_FRAMES != null)
74228
{
75229
this.frames = SHARED_FRAMES;
76-
var variant:String = pickVariant();
230+
var variant:String = this.variant;
231+
if (variant == null)
232+
variant = pickVariant();
77233
if (variant != null)
78234
{
79235
var names = VARIANT_FRAMES.get(variant);

source/PlayState.hx

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package;
22

33
import flixel.FlxG;
4+
import flixel.FlxSprite;
45
import flixel.FlxState;
56
import flixel.group.FlxGroup.FlxTypedGroup;
67
import flixel.math.FlxPoint;
8+
import ui.Hud;
79

810
class PlayState extends FlxState
911
{
@@ -14,6 +16,9 @@ class PlayState extends FlxState
1416
// enemies group (rendered above player, below reticle)
1517
public var enemies:FlxTypedGroup<Enemy>;
1618

19+
// HUD
20+
public var hud:Hud;
21+
1722
override public function create():Void
1823
{
1924
Actions.init();
@@ -34,16 +39,23 @@ class PlayState extends FlxState
3439
reticle = new Reticle(player);
3540
add(reticle);
3641

42+
// HUD group (separate class)
43+
hud = new Hud(player);
44+
add(hud);
45+
3746
FlxG.camera.setScrollBoundsRect(0, 0, Std.int(tilemap.width), Std.int(tilemap.height), true);
3847
FlxG.camera.follow(player);
3948
super.create();
4049
}
4150

51+
// ...existing code...
52+
4253
override public function update(elapsed:Float):Void
4354
{
4455
playerMovement(elapsed);
4556
if (reticle != null)
4657
reticle.updateFromPlayer(player);
58+
// HUD updates handled by Hud.update()
4759
super.update(elapsed);
4860
FlxG.collide(player, tilemap.wallsMap);
4961
}
@@ -104,16 +116,39 @@ class PlayState extends FlxState
104116
player.stop();
105117
}
106118
move.put();
119+
// handle attack/photo input
120+
if (Actions.attack.check())
121+
{
122+
if (player.tryTakePhoto())
123+
{
124+
// use FlxG.overlap to leverage HaxeFlixel collision logic (handles groups,
125+
// origin offsets and any custom overlap callbacks). We'll capture the first
126+
// enemy we find under the reticle and call capture on it.
127+
var hits:Array<Enemy> = [];
128+
FlxG.overlap(reticle, enemies, function(a:Dynamic, b:Dynamic):Void
129+
{
130+
if (b != null)
131+
hits.push(cast(b, Enemy));
132+
});
133+
// capture all hits found (rare case). We capture after collecting
134+
// to avoid mutating the group while FlxG.overlap is iterating.
135+
for (h in hits)
136+
{
137+
if (h != null)
138+
h.capture(player);
139+
}
140+
}
141+
}
107142
}
108143
// spawn enemies into rooms (skip portal room and corridors)
109144
private function spawnEnemies():Void
110145
{
111146
if (tilemap == null || tilemap.roomsInfo == null)
112147
return;
113148
var TILE_SIZE:Int = Constants.TILE_SIZE;
114-
var tilesPerEnemy:Int = 18; // require roughly this many tiles per enemy (sparser)
115-
var maxPerRoom:Int = 6;
116-
var globalMax:Int = 30; // reduce overall enemy count approx. in half
149+
var tilesPerEnemy:Int = 14; // was 18, reduced to increase density (~+20%)
150+
var maxPerRoom:Int = 7; // was 6
151+
var globalMax:Int = 36; // was 30
117152
var totalSpawned:Int = 0;
118153

119154
// screen-based density cap: no more than 1 enemy per quarter-screen area

0 commit comments

Comments
 (0)