Skip to content

Commit

Permalink
sprite builder mvp
Browse files Browse the repository at this point in the history
  • Loading branch information
jerzakm committed Nov 23, 2023
1 parent 74d17ff commit 6faf273
Show file tree
Hide file tree
Showing 29 changed files with 368 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<script lang="ts">
import {
InstancedSpriteMesh,
makeDataTexture,
parseAseprite
parseAseprite,
type SpritesheetFormat
} from '@threejs-kit/instanced-sprite-mesh';
import { T, useFrame, useLoader, useThrelte, watch } from '@threlte/core';
import {
Expand All @@ -11,11 +11,8 @@
LinearFilter,
Matrix4,
MeshBasicMaterial,
MeshStandardMaterial,
NearestFilter,
PlaneGeometry,
RepeatWrapping,
ShaderMaterial,
type Texture,
type Vector3Tuple
} from 'three';
Expand All @@ -25,7 +22,7 @@
AnimatedInstancedSpriteSlots
} from './AnimatedInstancedSprite.svelte';
import { useSuspense, useTexture } from '@threlte/extras';
import { useTexture } from '@threlte/extras';
import { setContext } from 'svelte';
import { writable } from 'svelte/store';
Expand All @@ -46,15 +43,16 @@
// export let transparent: $$Props['transparent'] = true
// export let flipX: $$Props['flipX'] = false
export let texture: Texture | undefined = undefined;
export let spritesheet: SpritesheetFormat | undefined = undefined;
const baseMaterial = new MeshBasicMaterial({
transparent: true,
alphaTest: 0.01,
// needs to be double side for shading
side: DoubleSide
});
const suspend = useSuspense();
type SpriteAnimations =
| 'RunRight'
| 'RunLeft'
Expand All @@ -70,40 +68,48 @@
count
);
const textureStore = suspend(
useTexture(textureUrl, {
transform: (value: Texture) => {
value.matrixAutoUpdate = false;
value.generateMipmaps = false;
value.premultiplyAlpha = false;
value.wrapS = value.wrapT = RepeatWrapping;
value.magFilter = value.minFilter = filter === 'nearest' ? NearestFilter : LinearFilter;
return value;
}
})
);
const textureStore = texture
? writable(texture)
: useTexture(textureUrl, {
transform: (value: Texture) => {
value.matrixAutoUpdate = false;
value.generateMipmaps = false;
value.premultiplyAlpha = false;
value.wrapS = value.wrapT = RepeatWrapping;
value.magFilter = value.minFilter = filter === 'nearest' ? NearestFilter : LinearFilter;
return value;
}
});
watch(textureStore, () => {
mesh.material.map = $textureStore;
mesh.material.needsUpdate = true;
});
const jsonStore = useLoader(FileLoader).load(dataUrl, {
transform: (file) => {
if (typeof file !== 'string') return;
try {
return JSON.parse(file);
} catch {
return;
}
}
});
const jsonStore = spritesheet
? writable(spritesheet)
: useLoader(FileLoader).load(dataUrl, {
transform: (file) => {
if (typeof file !== 'string') return;
try {
return JSON.parse(file);
} catch {
return;
}
}
});
const animationMap = writable<Map<SpriteAnimations, number>>(new Map());
watch(jsonStore, (rawSpritesheet) => {
if (rawSpritesheet) {
if (rawSpritesheet && !spritesheet) {
const spritesheet = parseAseprite(rawSpritesheet);
console.log({ spritesheet });
mesh.spritesheet = spritesheet;
animationMap.set(mesh.animationMap);
}
if (spritesheet) {
mesh.spritesheet = spritesheet;
animationMap.set(mesh.animationMap);
}
Expand All @@ -118,11 +124,6 @@
$: {
if ($textureStore && mesh.material && !initialized && mesh) {
mesh.castShadow = true;
mesh.tint.setGlobal({
h: 2,
s: 1,
v: 1
});
}
}
Expand Down
106 changes: 106 additions & 0 deletions apps/playground/src/routes/instanced-sprite/FlyerUpdater.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<script lang="ts">
import { useFrame, watch, T, useThrelte } from '@threlte/core';
import { getContext } from 'svelte';
import { SphereGeometry, Vector2 } from 'three';
const spriteCtx: any = getContext('instanced-sprite-ctx');
const { updatePosition, count, animationMap, setAnimation, mesh } = spriteCtx;
//@ts-ignore
watch(animationMap, (anims: Map<string, number>) => {
// console.log(anims.keys());
});
// mesh.material.uniforms.animationId.value = 0;
mesh.animation.setGlobal('fly');
console.log(mesh);
const posX: number[] = new Array(count).fill(0);
const posY: number[] = new Array(count).fill(0);
const posZ: number[] = new Array(count).fill(0);
const spread = 80;
const minCenterDistance = 0.5;
const maxCenterDistance = spread;
const rndPosition: any = () => {
const x = Math.random() * spread - spread / 2;
const y = Math.random() * spread - spread / 2;
/** min distance from 0,0. Recursive reroll if too close */
if (Math.sqrt(x ** 2 + y ** 2) < minCenterDistance) {
return rndPosition();
}
return { x, y };
};
/** update from 1 because 0 is user controlled and set at 0,0 */
for (let i = 1; i < count; i++) {
const pos = rndPosition();
posX[i] = pos.x;
posY[i] = 2 + Math.random() * 10;
posZ[i] = pos.y;
}
type Agent = {
action: 'Idle' | 'Run';
velocity: [number, number];
timer: number;
};
const agents: Agent[] = [];
for (let i = 0; i < count; i++) {
agents.push({
action: 'Run',
timer: 0.1,
velocity: [0, 1]
});
}
const velocityHelper = new Vector2(0, 0);
const updateAgents = (delta: number) => {
for (let i = 0; i < agents.length; i++) {
// timer
agents[i].timer -= delta;
// apply velocity
posX[i] += agents[i].velocity[0] * delta;
posZ[i] += agents[i].velocity[1] * delta;
// roll new behaviour when time runs out or agent gets out of bounds
if (i > 0) {
const dist = Math.sqrt((posX[i] || 0) ** 2 + (posZ[i] || 0) ** 2);
if (agents[i].timer < 0 || dist < minCenterDistance || dist > maxCenterDistance) {
const runChance = 0.6 + (agents[i].action === 'Idle' ? 0.3 : 0);
agents[i].action = Math.random() < runChance ? 'Run' : 'Idle';
agents[i].timer = 5 + Math.random() * 5;
if (agents[i].action === 'Run') {
velocityHelper
.set(Math.random() - 0.5, Math.random() - 0.5)
.normalize()
.multiplyScalar(0.1);
agents[i].velocity = velocityHelper.toArray();
}
}
}
}
};
useFrame((_, _delta) => {
if ($animationMap.size > 0) {
updateAgents(_delta);
}
for (let i = 0; i < count; i++) {
// $camera.position.set(0 + (posX[0] || 0), 7, 15 + (posZ[0] || 0))
updatePosition(i, [posX[i] || 0, posY[i] || 0, posZ[i] || 0]);
}
});
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//@ts-ignore
watch(animationMap, (anims: Map<string, number>) => {
console.log(anims.keys());
// console.log(anims.keys());
});
const posX: number[] = new Array(count).fill(0);
Expand Down
41 changes: 39 additions & 2 deletions apps/playground/src/routes/instanced-sprite/Scene.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,39 @@
import PlayerUpdater from './PlayerUpdater.svelte';
import { DEG2RAD } from 'three/src/math/MathUtils.js';
import AnimatedInstancedSprite from './AnimatedInstancedSprite.svelte';
import { SpriteBuilder } from './spriteBuilder';
import FlyerUpdater from './FlyerUpdater.svelte';
const count = 50000;
const monster = new SpriteBuilder();
const g = monster
.add('fly', '/textures/sprites/Monsters_Creatures_Fantasy/Flying_eye/Flight.png', {
type: 'rowColumn',
w: 8,
h: 1,
rowMajor: true
})
.add('attack', '/textures/sprites/Monsters_Creatures_Fantasy/Flying_eye/Attack.png', {
type: 'rowColumn',
w: 8,
h: 1,
rowMajor: true
})
.add('death', '/textures/sprites/Monsters_Creatures_Fantasy/Flying_eye/Death.png', {
type: 'rowColumn',
w: 4,
h: 1,
rowMajor: true
})
.add('hit', '/textures/sprites/Monsters_Creatures_Fantasy/Flying_eye/Hit.png', {
type: 'rowColumn',
w: 4,
h: 1,
rowMajor: true
})
.build();
</script>

<T.PerspectiveCamera makeDefault position.z={15} position.y={7}>
Expand All @@ -14,15 +45,21 @@

<slot />

<AnimatedInstancedSprite
<!-- <AnimatedInstancedSprite
textureUrl="/textures/sprites/player.png"
dataUrl="/textures/sprites/player.json"
fps={10}
loop={true}
{count}
>
<PlayerUpdater />
</AnimatedInstancedSprite>
</AnimatedInstancedSprite> -->

{#await g then { spritesheet, texture }}
<AnimatedInstancedSprite {spritesheet} {texture} fps={10} loop={true} {count}>
<FlyerUpdater />
</AnimatedInstancedSprite>
{/await}

<Sky elevation={0.15} />
<!-- <T.AmbientLight /> -->
Expand Down
Loading

1 comment on commit 6faf273

@vercel
Copy link

@vercel vercel bot commented on 6faf273 Nov 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

threejs-kit-playground – ./apps/playground

threejs-kit-playground-git-main-jerzakm.vercel.app
threejs-kit-playground-jerzakm.vercel.app
threejs-kit-playground.vercel.app

Please sign in to comment.