Add some particle effects

This commit is contained in:
thepaperpilot 2023-02-19 23:13:23 -06:00
parent bd8495ffbf
commit caa3783c4b
6 changed files with 185 additions and 2 deletions

BIN
public/particle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 629 B

View file

@ -79,11 +79,13 @@
<img :src="level2_2" v-if="character.exp === 5" /> <img :src="level2_2" v-if="character.exp === 5" />
<img :src="level3" v-if="character.exp === 6" /> <img :src="level3" v-if="character.exp === 6" />
</span> </span>
<Node v-if="id" :id="id" />
</div> </div>
</Tooltip> </Tooltip>
</template> </template>
<script setup lang="tsx"> <script setup lang="tsx">
import Node from "components/Node.vue";
import { jsx, JSXFunction } from "features/feature"; import { jsx, JSXFunction } from "features/feature";
import Tooltip from "features/tooltips/Tooltip.vue"; import Tooltip from "features/tooltips/Tooltip.vue";
import { Direction } from "util/common"; import { Direction } from "util/common";
@ -100,6 +102,7 @@ import { characters } from "./projEntry";
import { Character } from "./types"; import { Character } from "./types";
const props = defineProps<{ const props = defineProps<{
id?: string;
character?: Character | null; character?: Character | null;
isSelected?: boolean; isSelected?: boolean;
isShop?: boolean; isShop?: boolean;

133
src/data/particle.json Normal file
View file

@ -0,0 +1,133 @@
{
"lifetime": {
"min": 0.25,
"max": 0.5
},
"ease": [
{
"s": 0,
"cp": 0.329,
"e": 0.548
},
{
"s": 0.548,
"cp": 0.767,
"e": 0.876
},
{
"s": 0.876,
"cp": 0.985,
"e": 1
}
],
"frequency": 0.01,
"emitterLifetime": 0.1,
"maxParticles": 100,
"addAtBack": true,
"pos": {
"x": 0,
"y": 0
},
"emit": false,
"behaviors": [
{
"type": "alpha",
"config": {
"alpha": {
"list": [
{
"time": 0,
"value": 0.74
},
{
"time": 1,
"value": 0
}
]
}
}
},
{
"type": "moveSpeed",
"config": {
"speed": {
"list": [
{
"time": 0,
"value": 100
},
{
"time": 1,
"value": 0
}
]
},
"minMult": 1
}
},
{
"type": "scale",
"config": {
"scale": {
"list": [
{
"time": 0,
"value": 2
},
{
"time": 1,
"value": 0.5
}
]
},
"minMult": 1
}
},
{
"type": "color",
"config": {
"color": {
"list": [
{
"time": 0,
"value": "#FFC000"
},
{
"time": 1,
"value": "#FFDF00"
}
]
}
}
},
{
"type": "rotation",
"config": {
"accel": 0,
"minSpeed": 0,
"maxSpeed": 200,
"minStart": 0,
"maxStart": 360
}
},
{
"type": "textureRandom",
"config": {
"textures": [
"/particle.png"
]
}
},
{
"type": "spawnShape",
"config": {
"type": "torus",
"data": {
"radius": 100,
"x": 0,
"y": 0
}
}
}
]
}

View file

@ -23,6 +23,9 @@ import { createReset } from "features/reset";
import settings from "game/settings"; import settings from "game/settings";
import type { AbilityTypes, CharacterInfo, Character, BattleOutcome } from "./types"; import type { AbilityTypes, CharacterInfo, Character, BattleOutcome } from "./types";
import { formatWhole } from "util/bignum"; import { formatWhole } from "util/bignum";
import particles from "./particle.json";
import { createParticles } from "features/particles/particles";
import { render } from "util/vue";
export const characters: Record<string, CharacterInfo> = { export const characters: Record<string, CharacterInfo> = {
coots: { coots: {
@ -252,6 +255,15 @@ export const main = createLayer("main", function (this: BaseLayer) {
} }
} }
const particles = createParticles(() => ({
fullscreen: false,
zIndex: 10,
boundingRect: ref<null | DOMRect>(null),
onContainerResized(boundingRect) {
this.boundingRect.value = boundingRect;
}
}));
return { return {
name: "Game", name: "Game",
minimizable: false, minimizable: false,
@ -445,6 +457,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
<Row style="margin-top: 10vh"> <Row style="margin-top: 10vh">
{new Array(3).fill(0).map((_, i) => ( {new Array(3).fill(0).map((_, i) => (
<CharacterSlot <CharacterSlot
id={`team-char-${i}`}
character={team.value[i]} character={team.value[i]}
isSelected={selectedCharacter.value === i} isSelected={selectedCharacter.value === i}
selected={ selected={
@ -493,6 +506,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
</div> </div>
{shop.value.map((item, i) => ( {shop.value.map((item, i) => (
<CharacterSlot <CharacterSlot
id={`shop-char-${i}`}
character={item == null ? undefined : item} character={item == null ? undefined : item}
isSelected={selectedShopItem.value === i} isSelected={selectedShopItem.value === i}
isShop={true} isShop={true}
@ -533,6 +547,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
src={startStream} src={startStream}
/> />
)} )}
{render(particles)}
</div> </div>
); );
}), }),
@ -550,7 +565,8 @@ export const main = createLayer("main", function (this: BaseLayer) {
reset, reset,
battle, battle,
playClicked, playClicked,
prepareMove prepareMove,
particles
}; };
}); });

View file

@ -7,8 +7,9 @@ import satisfies from "semver/functions/satisfies";
import { io, Socket } from "socket.io-client"; import { io, Socket } from "socket.io-client";
import { ref, watch } from "vue"; import { ref, watch } from "vue";
import { useToast } from "vue-toastification"; import { useToast } from "vue-toastification";
import particle from "./particle.json";
import { characters, main } from "./projEntry"; import { characters, main } from "./projEntry";
import { ServerToClientEvents, ClientToServerEvents, Character } from "./types"; import { ClientToServerEvents, ServerToClientEvents } from "./types";
export const connected = ref<boolean>(false); export const connected = ref<boolean>(false);
export const nickname = ref<string>(""); export const nickname = ref<string>("");
@ -70,6 +71,23 @@ globalBus.on("loadSettings", settings => {
); );
}); });
function poof(id: string) {
const boundingRect = main.particles.boundingRect.value;
if (!boundingRect) {
return;
}
const rect = main.nodes.value[id]?.rect;
if (rect) {
main.particles.addEmitter(particle).then(e => {
e.updateOwnerPos(
rect.x + rect.width / 2 - boundingRect.x,
rect.y + rect.height / 2 - boundingRect.y
);
e.playOnceAndDestroy();
});
}
}
function setupSocket(socket: Socket<ServerToClientEvents, ClientToServerEvents>) { function setupSocket(socket: Socket<ServerToClientEvents, ClientToServerEvents>) {
socket.on("connect", () => { socket.on("connect", () => {
connectionError.value = ""; connectionError.value = "";
@ -113,6 +131,9 @@ function setupSocket(socket: Socket<ServerToClientEvents, ClientToServerEvents>)
presence: characters[item].initialPresence, presence: characters[item].initialPresence,
exp: 1 exp: 1
})); }));
setTimeout(() => {
shop.forEach((_, i) => poof(`shop-char-${i}`));
}, 0);
}); });
socket.on("reroll", shop => { socket.on("reroll", shop => {
main.gold.value--; main.gold.value--;
@ -122,20 +143,29 @@ function setupSocket(socket: Socket<ServerToClientEvents, ClientToServerEvents>)
presence: characters[item].initialPresence, presence: characters[item].initialPresence,
exp: 1 exp: 1
})); }));
setTimeout(() => {
shop.forEach((_, i) => poof(`shop-char-${i}`));
}, 0);
}); });
socket.on("buy", (shopIndex, teamIndex, char) => { socket.on("buy", (shopIndex, teamIndex, char) => {
main.team.value[teamIndex] = char; main.team.value[teamIndex] = char;
main.shop.value[shopIndex] = null; main.shop.value[shopIndex] = null;
main.gold.value -= 3; main.gold.value -= 3;
poof(`shop-char-${shopIndex}`);
poof(`team-char-${teamIndex}`);
}); });
socket.on("move", (index, otherIndex) => { socket.on("move", (index, otherIndex) => {
const temp = main.team.value[index]; const temp = main.team.value[index];
main.team.value[index] = main.team.value[otherIndex]; main.team.value[index] = main.team.value[otherIndex];
main.team.value[otherIndex] = temp; main.team.value[otherIndex] = temp;
poof(`team-char-${index}`);
poof(`team-char-${otherIndex}`);
}); });
socket.on("merge", (index, otherIndex, char) => { socket.on("merge", (index, otherIndex, char) => {
main.team.value[index] = null; main.team.value[index] = null;
main.team.value[otherIndex] = char; main.team.value[otherIndex] = char;
poof(`team-char-${index}`);
poof(`team-char-${otherIndex}`);
}); });
socket.on("stream", (enemy, outcome) => { socket.on("stream", (enemy, outcome) => {
main.findingMatch.value = false; main.findingMatch.value = false;

View file

@ -90,5 +90,6 @@ export default defineComponent({
right: -4px; right: -4px;
bottom: 5px; bottom: 5px;
pointer-events: none; pointer-events: none;
z-index: 10;
} }
</style> </style>