create animation with zip of frame

This commit is contained in:
NekoVari 2024-12-17 17:36:53 +07:00
parent cad7c8f84e
commit 71e597158d
4 changed files with 45 additions and 51 deletions

View file

@ -1,9 +1,9 @@
import * as React from 'react'; import * as React from 'react';
import { StrictMode } from 'react' import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client' import { createRoot } from 'react-dom/client';
import { BrowserRouter, Routes, Route } from 'react-router-dom'; import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import './css/global.css' import './css/global.css';
import HomePage from './pages/homePage.jsx' import HomePage from './pages/homePage.jsx';
import WarningPage from './pages/warningPage.jsx'; import WarningPage from './pages/warningPage.jsx';
import NamePage from './pages/namePage.jsx'; import NamePage from './pages/namePage.jsx';
import Animation from './pages/components/testAnimation_onefile.jsx'; import Animation from './pages/components/testAnimation_onefile.jsx';
@ -14,9 +14,10 @@ createRoot(document.getElementById('root')).render(
<Routes> <Routes>
<Route path="/" element={<HomePage />} /> <Route path="/" element={<HomePage />} />
<Route path="/warn" element={<WarningPage />} /> <Route path="/warn" element={<WarningPage />} />
<Route path="/name" element={<NamePage />}/> <Route path="/name" element={<NamePage />} />
<Route path="/sprite" element={<Animation />}/> <Route path="/sprite" element={<Animation />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes> </Routes>
</BrowserRouter> </BrowserRouter>
</StrictMode>, </StrictMode>,
) );

View file

@ -1,47 +1,43 @@
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import anime from 'animejs'; import anime from 'animejs';
const startNumber = 1000; // Starting number const startNumber = 1000;
const endNumber = 1239; // Ending number const endNumber = 1239;
const imageCount = endNumber - startNumber + 1; // Total number of images const imageCount = endNumber - startNumber + 1;
const images = []; const images = [];
// Loop through the range from startNumber to endNumber
for (let i = startNumber; i <= endNumber; i++) { for (let i = startNumber; i <= endNumber; i++) {
// Format the number to be 5 digits with leading zeros
const formattedNumber = String(i).padStart(5, '0'); const formattedNumber = String(i).padStart(5, '0');
images.push(import(`../../assets/characters/F_porche_akimbo_AME/Porsche${formattedNumber}.png`)); images.push(import(`../../assets/characters/F_porche_akimbo_AME/Porsche${formattedNumber}.png`));
} }
const CharacterAnimation = () => { const CharacterAnimation = () => {
const totalFrames = imageCount; // Total number of frames const totalFrames = imageCount;
const frameDuration = 20; // Duration for each frame in milliseconds const frameDuration = 20;
const [currentFrame, setCurrentFrame] = useState(0); const [currentFrame, setCurrentFrame] = useState(0);
const [loadedImages, setLoadedImages] = useState([]); // State to hold loaded images const [loadedImages, setLoadedImages] = useState([]);
const characterRef = useRef(null); const characterRef = useRef(null);
useEffect(() => { useEffect(() => {
// Load all images
Promise.all(images).then((resolvedImages) => { Promise.all(images).then((resolvedImages) => {
setLoadedImages(resolvedImages.map(image => image.default)); // Set the loaded images setLoadedImages(resolvedImages.map(image => image.default));
}); });
}, []); }, []);
useEffect(() => { useEffect(() => {
const interval = setInterval(() => { const interval = setInterval(() => {
setCurrentFrame((prevFrame) => (prevFrame + 1) % totalFrames); setCurrentFrame((prevFrame) => (prevFrame + 1) % totalFrames);
console.log(loadedImages)
}, frameDuration); }, frameDuration);
return () => clearInterval(interval); // Cleanup on unmount return () => clearInterval(interval);
}, []); }, []);
return ( return (
<img <img
ref={characterRef} ref={characterRef}
src={loadedImages[currentFrame]} // Use the loaded images src={loadedImages[currentFrame]}
alt="Character Animation" alt="Character Animation"
style={{ width: '200px', height: 'auto' }} // Adjust size as needed style={{ width: '200px', height: 'auto' }}
/> />
); );
}; };

View file

@ -5,13 +5,13 @@ const Animation = () => {
const [images, setImages] = useState([]); const [images, setImages] = useState([]);
const [currentFrame, setCurrentFrame] = useState(0); const [currentFrame, setCurrentFrame] = useState(0);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const frameRate = 100; // Frame rate in milliseconds const frameRate = 60;
useEffect(() => { useEffect(() => {
const loadImages = async () => { const loadImages = async () => {
const zip = new JSZip(); const zip = new JSZip();
try { try {
const response = await fetch('src/assets/characters/sprite.zip'); // Adjust the path to your ZIP file const response = await fetch('src/assets/characters/M_Porsche_cross_arm.zip');
if (!response.ok) { if (!response.ok) {
throw new Error('Network response was not ok'); throw new Error('Network response was not ok');
} }
@ -21,20 +21,27 @@ const Animation = () => {
const imgPromises = []; const imgPromises = [];
zipContent.forEach((relativePath, file) => { zipContent.forEach((relativePath, file) => {
if (file.name.endsWith('.webp')) { if (file.name.endsWith('.webp')) {
imgPromises.push(file.async('blob')); // Convert file to Blob imgPromises.push(
file.async('base64').then(base64 => {
return `data:image/webp;base64,${base64}`;
})
);
} }
}); });
const imgBlobs = await Promise.all(imgPromises); const imgUrls = await Promise.all(imgPromises);
const imgUrls = imgBlobs.map(blob => URL.createObjectURL(blob)); // Create object URLs
console.log('Loaded images:', imgUrls); // Log the loaded image URLs // console.log('Loaded images:', imgUrls);
if (imgUrls.length === 0) {
console.error('No images found in the ZIP file.');
}
setImages(imgUrls); setImages(imgUrls);
} catch (error) { } catch (error) {
console.error('Error loading images:', error); console.error('Error loading images:', error);
} finally { } finally {
setLoading(false); // Set loading to false after images are loaded setLoading(false);
} }
}; };
@ -43,31 +50,28 @@ const Animation = () => {
}, []); }, []);
useEffect(() => { useEffect(() => {
const interval = setInterval(() => { if (images.length > 0) {
setCurrentFrame((prevFrame) => (prevFrame + 1) % images.length); const interval = setInterval(() => {
}, frameRate); setCurrentFrame((prevFrame) => (prevFrame + 1) % images.length);
}, frameRate);
return () => clearInterval(interval); return () => clearInterval(interval);
}, [images]); }
useEffect(() => {
// Cleanup object URLs when the component unmounts
return () => {
images.forEach(url => URL.revokeObjectURL(url)); // Clean up object URLs
};
}, [images]); }, [images]);
if (loading) { if (loading) {
return <div>Loading...</div>; // Show loading indicator return <div>Loading...</div>;
} else { } else {
return ( return (
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}> <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
{images.length > 0 && ( {images.length > 0 ? (
<img <img
src={images[currentFrame]} src={images[currentFrame]}
alt="Animation frame" alt={`Animation frame ${currentFrame + 1}`}
style={{ maxWidth: '100%', height: 'auto' }} // Responsive image style={{ maxWidth: '500px', height: 'auto' }}
/> />
) : (
<div>No images to display.</div>
)} )}
</div> </div>
); );

View file

@ -1,8 +1,6 @@
import { useState } from 'react' import { useState } from 'react'
import '../css/global.css' import '../css/global.css'
import BlackButton from './components/customButton' import BlackButton from './components/customButton'
import SpriteAnimation from './components/testAnimation_onefile'
import CharacterAnimation from './components/testAnimation_manyfiles'
function HomePage() { function HomePage() {
@ -19,11 +17,6 @@ function HomePage() {
<div style={{ height: '8vh' }}/> <div style={{ height: '8vh' }}/>
<CharacterAnimation/>
{/* <SpriteAnimation/> */}
<div style={{ height: '8vh' }}/>
<BlackButton text="Start" to='/warn'/> <BlackButton text="Start" to='/warn'/>
</div> </div>
) )