Start typing to search packages!
rain-particle
By @hakochanjp
Roblox
MirroredRainParticle
カメラまたは自キャラの周辺にパーティクルを降らせる Roblox 向け クライアント専用 モジュール。
⚠️ クライアント専用:
requireとRainParticle.newはLocalScript/RunContext = Clientのスクリプトからのみ呼び出してください。サーバー側でnewを呼ぶと error します。
特徴
- カメラ / キャラ追従 —
FollowTargetで基準点を切り替え可能(キャラがリスポーン中は自動でカメラにフォールバック) - Template ベースの見た目 — Studio Explorer で作り込んだ
ParticleEmitterを渡すだけでその見た目を再現 - Rain / Snow プリセット同梱 —
RainParticle.Preset.Rain(template)/RainParticle.Preset.Snow(template)でいきなり使える - 複数インスタンス同時稼働 — クラス設計のため「豪雨+霧+桜吹雪」などのレイヤー演出が可能
- 落下制御ロック —
FallSpeed/FallDistanceから Lifetime を自動計算し、実際の落下距離が保証される - 軽量実装 — パーティクルごとに Part を作らず Attachment を使用
- Strict モード —
--!strict、selene / stylua で品質チェック済み
インストール
利用側プロジェクトの wally.toml:
[dependencies]
RainParticle = "hakochanjp/rain-particle@0.2.0"
そして wally install で Packages/RainParticle が生成される。
使い方
最小サンプル
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Packages = ReplicatedStorage:WaitForChild("Packages")
local RainParticle = require(Packages.RainParticle)
-- Studio Explorer で作った ParticleEmitter を Template として用意
local template = ReplicatedStorage:WaitForChild("MyRainTemplate") :: ParticleEmitter
local rain = RainParticle.new({
FollowTarget = RainParticle.Enum.FollowTarget.Character,
Template = template,
Rate = 100,
AreaSize = Vector3.new(60, 1, 60),
Height = 25,
ForwardOffset = 20,
FallSpeed = 30,
FallDistance = 50,
})
rain:Start()
動作中の設定更新
-- Rate だけ変える(ループは止まらない)
rain:Update({ Rate = 500 })
-- 一時停止(破棄せず生成だけ止める)
rain:Update({ Rate = 0 })
-- 見た目だけ差し替え
rain:Update({
EmitterProperties = {
Color = ColorSequence.new(Color3.fromRGB(180, 220, 255)),
LightEmission = 0.3,
},
})
EmitterProperties のリセット
差分マージ仕様のため、一度設定した値は同じキーを再指定するまで残ります。「未指定状態に戻す」場合は RainParticle.None sentinel を使ってください。
-- 全クリア(Template 由来の見た目に戻す)
rain:Update({ EmitterProperties = RainParticle.None })
-- 特定キーだけ取り消し
rain:Update({ EmitterProperties = { LightEmission = RainParticle.None } })
なお Update({ EmitterProperties = {} }) は「変更なし」として扱われます。
粒単位オクルージョン(Occlusion)
Occlusion = true を指定すると、生成点の直上 Raycast で屋内判定を行い、屋内なら該当粒をスポーンしません。さらに落下経路上の下向き Raycast で屋根・庇等の遮蔽面に当たった場合は Lifetime をその距離にクランプし、粒が遮蔽面でちょうど消えるようにします(既定 false・完全後方互換)。
-- 粒単位オクルージョン: 屋内にスポーンせず、屋根で粒が止まる
local rain = RainParticle.new(RainParticle.Preset.Rain(nil, {
Occlusion = true,
}))
rain:Start()
OcclusionParams: RaycastParams? で Raycast のフィルタを上書きできます(省略時の既定: Exclude 空 / IgnoreWater = true / RespectCanCollide = false)。RainParticle.None を渡すと未指定状態に戻せます。
💡 近似・制約:Lifetime クランプは鉛直落下前提のため、
SpreadAngle等で粒を斜めに飛ばすと消える位置は近似になります(既定テンプレートは真下落下)。透明パーツ(ガラス等)も遮蔽として扱われます。下向き Raycast はキャラクターにもヒットします(雨が人に当たって消える見た目)。コスト目安は 1 粒あたり最大 2 Raycast(Rate 600/s で毎フレーム約 20 本)。
プリセット(Rain / Snow)
主要パターン用の工場関数を同梱しています。Template は省略可能で、省略するとリポジトリ同梱のテクスチャ(hakochanjp アカウントにアップロード済み)を使います。
-- もっとも短い書き方:同梱テクスチャでそのまま動く
local rain = RainParticle.new(RainParticle.Preset.Rain())
rain:Start()
-- 同梱テクスチャ + override
local snow = RainParticle.new(RainParticle.Preset.Snow(nil, {
Rate = 40,
FallSpeed = 8,
}))
snow:Start()
-- 自前テクスチャを使いたい場合
local myTemplate = Instance.new("ParticleEmitter")
myTemplate.Texture = "rbxassetid://<your_image_id>"
local custom = RainParticle.new(RainParticle.Preset.Rain(myTemplate))
custom:Start()
override の EmitterProperties はプリセットの EmitterProperties と per-key マージされます(RainParticle.None で削除も可)。override.Template は無視され、常に第 1 引数の Template(または同梱)が採用されます。
同梱テクスチャ
| プリセット | テクスチャ | サイズ | Image ID | 用途 |
|---|---|---|---|---|
Preset.Rain | assets/rain_streak.png | 512 × 512 | 97568157179715 | square 中央に 1 本の雨粒 streak(水平方向に描画 → VelocityParallel で 90° 回転して縦の雨に) |
Preset.Snow | assets/snow_dot.png | 128 × 128 | 127825484280482 | radial フェードの柔らかい白丸 |
Image ID は RainParticle.Preset.RainTextureId / RainParticle.Preset.SnowTextureId でも参照できます(自作 ParticleEmitter で同じテクスチャを使いたいときに便利)。
⚠️ 本番運用時の注意:同梱テクスチャは「お試し用」です
Preset.Rain()/Preset.Snow()の 引数なし形式が参照するテクスチャは hakochanjp 個人アカウントにホストされています。Roblox のモデレーション・アカウント凍結・将来的な削除などが起きると、downstream の本番ゲームの雨/雪が黙って消えたり透明な四角になる可能性があります。本番プロジェクトでは必ず以下のいずれかにしてください:
- 推奨:
assets/rain_streak.png/assets/snow_dot.pngを自分のアカウントに再アップロードし、Preset.Rain(myTemplate)の形で自前 Template を渡す- または
Preset.RainTextureId/Preset.SnowTextureIdを参照しつつ、リスクを自分で受け入れる-- 推奨パターン local myTemplate = Instance.new("ParticleEmitter") myTemplate.Texture = "rbxassetid://<自分でアップロードした image id>" local rain = RainParticle.new(RainParticle.Preset.Rain(myTemplate)) rain:Start()
💡 Decal ID と Image ID の違い:Asset Manager 経由でアップロードすると Decal(AssetTypeId=13)の ID が表示されますが、
ParticleEmitter.Textureが要求するのは内側の Image(AssetTypeId=1)の ID です。Studio 上で Asset Manager から Template にドラッグ&ドロップすると自動的に Image ID が入りますが、ID を手で貼り付ける場合は次のように内側 ID を抽出してください。-- 編集モードのコマンドバーで実行 local model = game:GetService("InsertService"):LoadAsset(<DECAL_ID>) print(model:FindFirstChildOfClass("Decal").Texture) -- → rbxassetid://<IMAGE_ID>
複数レイヤー演出
local heavyRain = RainParticle.new(RainParticle.Preset.Rain(rainTemplate))
local snow = RainParticle.new(RainParticle.Preset.Snow(snowTemplate))
heavyRain:Start()
snow:Start()
すべてのインスタンスは workspace.RainParticleContainers 配下の子 Folder として整理されます。
停止・破棄
rain:Stop() -- スポーン停止(既存粒は自然消滅)。_accumulator もリセット
rain:Destroy() -- 完全破棄(既存粒も即座削除)
💡 一時停止と「停止」の使い分け:
- 短時間で再開する用途には
rain:Update({ Rate = 0 })を使う。PreRender 接続は維持され、Rate を戻すだけで即時再開できる。- 本当に止める(しばらく使わない / リソースを解放したい)場合は
rain:Stop()を使う。PreRender 接続が切断され、内部の_accumulatorも 0 にリセットされる。次の:Start()までスポーン処理は一切走らない。- 完全に捨てる場合は
rain:Destroy()。インスタンスを再利用しないなら必ずこれを呼ぶ。
動作中の Template 差し替え
Update({ Template = newTemplate }) で 動作中に Template を差し替え可能です。差し替え後にスポーンされる粒から新しい Template が使われます(既に飛んでいる粒は寿命まで旧 Template の見た目のまま)。
-- 雨 → 桜吹雪に切り替え(既存の雨粒はそのまま落ち切る)
rain:Update({ Template = sakuraTemplate })
なお Template は RainParticle.None での「未指定に戻す」操作はサポートしません(必ず ParticleEmitter インスタンスを渡してください)。
公開API
インスタンス生成
| 関数 | 説明 |
|---|---|
RainParticle.new(config: RainInitConfig): RainParticle | 新しいインスタンスを生成。Template は型レベルで必須 |
インスタンスメソッド
| メソッド | 説明 |
|---|---|
rain:Start(override: RainConfig?) | 生成開始。override を渡すと内部で Update してから起動 |
rain:Update(override: RainConfig) | 設定を差分マージ(起動状態は変えない)。値に RainParticle.None を渡すと未指定状態に戻る |
rain:Stop() | スポーン停止(container 保持、既存粒は自然消滅、_accumulator リセット) |
rain:Destroy() | リソース完全破棄 |
Enum / sentinel
RainParticle.Enum.FollowTarget.Camera— カメラ基準RainParticle.Enum.FollowTarget.Character— 自キャラ HumanoidRootPart 基準RainParticle.None—Update/ Preset override で「未指定状態に戻す」ことを表す sentinel(EmitterProperties のリセット参照)
プリセット工場関数
| 関数 | シグネチャ | 戻り値 |
|---|---|---|
RainParticle.Preset.Rain | (template: ParticleEmitter?, override: RainConfig?) -> RainInitConfig | マルチドロップ雨用の RainInitConfig |
RainParticle.Preset.Snow | (template: ParticleEmitter?, override: RainConfig?) -> RainInitConfig | ふんわり雪用の RainInitConfig |
RainParticle.Preset.RainTextureId | number 定数 | 同梱 rain_streak.png の Image asset ID |
RainParticle.Preset.SnowTextureId | number 定数 | 同梱 snow_dot.png の Image asset ID |
第 1 引数 template(任意): ベースとなる ParticleEmitter。省略または nil を渡すと同梱テクスチャを Texture にした ParticleEmitter を自動生成して使う。
第 2 引数 override(任意): プリセットのデフォルト値を per-key で上書きする差分。
- top-level(
Rate/Height等)はnil安全に上書き(Rate = 0も尊重される) EmitterPropertiesは base と incoming を per-key マージEmitterProperties = RainParticle.Noneで base の emitter props を完全クリアEmitterProperties = { Color = RainParticle.None }で個別キーだけ削除override.Templateは無視(常に第 1 引数の template が採用される)
デフォルト値
| プロパティ | Preset.Rain | Preset.Snow |
|---|---|---|
FollowTarget | "Camera" | "Camera" |
Rate | 400 | 80 |
AreaSize | Vector3.new(80, 1, 80) | Vector3.new(100, 1, 100) |
Height | 35 | 50 |
ForwardOffset | 15 | 20 |
FallSpeed | 120 | 12 |
FallDistance | 80 | 80 |
EmitterProperties.Color | ColorSequence.new(Color3.fromRGB(220, 235, 255)) | ColorSequence.new(Color3.fromRGB(255, 255, 255)) |
EmitterProperties.Size | NumberSequence.new(2) | NumberSequence.new(0.5) |
EmitterProperties.Transparency | NumberSequence.new(0.2) | NumberSequence.new(0.2) |
EmitterProperties.LightEmission | 0.1 | 0.2 |
EmitterProperties.LightInfluence | 0.5 | 0.3 |
EmitterProperties.Rotation | — | NumberRange.new(0, 360) |
EmitterProperties.RotSpeed | — | NumberRange.new(-30, 30) |
EmitterProperties.SpreadAngle | — | Vector2.new(15, 15) |
EmitterProperties.Orientation | Enum.ParticleOrientation.VelocityParallel | Enum.ParticleOrientation.FacingCamera |
💡
Preset.RainのVelocityParallelは テクスチャの U 軸を velocity 方向に揃える 仕様です。assets/rain_streak.pngは streak を 水平方向に描画している ため、落下時に 90° 回転して画面上は縦の雨として描画されます。キャラ移動時に少し傾く motion-aligned な見え方が得られます(縦長 streak テクスチャを使う場合はFacingCameraを選んでください)。
💡 Preset 専用のモジュールが
RainParticle.Preset(=src/Preset.luau)に分離されているため、local Preset = require(RainParticle.Preset)のように直接 require してPreset.Rain(...)/Preset.Snow(...)を呼ぶこともできます。
型エクスポート
| 型 | 用途 |
|---|---|
RainParticle.RainInitConfig | new() 用。Template 必須 |
RainParticle.RainConfig | Update / Start 用。全項目任意 |
RainParticle.RainParticle | インスタンス型 |
RainParticle.FollowTarget | "Camera" | "Character" |
RainConfig プロパティ一覧
| プロパティ | 型 | 説明 |
|---|---|---|
FollowTarget | "Camera" | "Character" | 追従対象(既定: Camera)。それ以外の値は error |
Rate | number | 毎秒の生成数(既定: 300)。0 で一時停止、負数は error |
AreaSize | Vector3 | 水平生成範囲(X/Z のみ使用、Y は無視) |
Height | number | 基準点からの上方オフセット(負値で下方) |
ForwardOffset | number | 基準点からの前方オフセット(負値で後方) |
FallSpeed | number | 落下速度(スタッド/秒)。正の数 |
FallDistance | number | 落下距離(スタッド)。正の数。Lifetime を自動計算 |
EmitterProperties | {[string]: any}? | ParticleEmitter の任意プロパティ辞書上書き。RainParticle.None でリセット |
Occlusion | boolean? | 粒単位オクルージョン(既定 false)。屋内ならスポーンせず、落下経路上の遮蔽面で Lifetime をクランプして粒を消す |
OcclusionParams | RaycastParams? | オクルージョン Raycast のフィルタ上書き。既定: Exclude 空 / IgnoreWater=true / RespectCanCollide=false。RainParticle.None でリセット |
Template | ParticleEmitter | new() で必須 ベース ParticleEmitter |
自動上書き(ロック)されるプロパティ
RainParticle の落下制御に必須のため、以下は Template / EmitterProperties で指定しても無視されます(警告が出ます)。
| プロパティ | 固定値 | 理由 |
|---|---|---|
Rate | 0 | 単発 Emit(1) で生成するため |
Lifetime | FallDistance / FallSpeed | 落下挙動と一致させる |
Speed | FallSpeed | 放出速度 = 落下速度 |
LockedToPart | false | 自然落下 |
VelocityInheritance | 0 | 基準点の移動を継承しない |
Drag | 0 | FallDistance 精度維持 |
Acceleration | Vector3.zero | 等速落下(workspace.Gravity の影響なし) |
WindAffectsDrag | false | GlobalWind の影響なし |
EmissionDirection | Bottom | 下向き放出(RainParticle 仕様) |
Enabled | true | Emit(1) のため。停止は Stop() または Rate = 0 を使う |
挙動を変えたい場合は FallSpeed / FallDistance で調整してください。
開発
rokit install # ツールチェーン(rojo / wally / stylua / selene)を導入
wally install # 依存パッケージを取得
rojo serve dev.project.json # Studio と同期
ディレクトリ構成
RobloxRainParticle/
├── src/ # ライブラリ本体(wally で配布)
│ └── init.luau
├── tests/ # 動作確認スクリプト(wally 配布対象外)
│ └── RainParticleTest/
├── assets/ # 推奨テクスチャ PNG(wally 配布対象外、要手動アップロード)
│ ├── rain_streak.png # Preset.Rain 用
│ └── snow_dot.png # Preset.Snow 用
├── default.project.json # リリース用 Rojo 設定(src のみ)
├── dev.project.json # 開発用 Rojo 設定(src + tests + Packages)
├── wally.toml
├── rokit.toml
├── stylua.toml
├── selene.toml
├── LICENSE
└── README.md
ライセンス
MIT License © 2026 hakochanjp
Package Details
Install command (Click to copy)
Version
0.3.0
License
MIT
Safe for commercial use
Automated license review — not legal advice.
