#vector3
Explore tagged Tumblr posts
Text
Okay tomorrow, armed with the things I have vaguely inferred, I try to fix the chatgpt code. It’s true it did a bunch of weird stuff once I started frightening it with the error messages. I’ve got to get it to quit doing anything with quaternions in the functions themselves, I think—though the set functions work, so I’ll leave them alone.
I just need to somehow get the literal plaintext localEulerAngles out of the .anim file, and use those numbers via the localEulerAngles function to set a new rotation Vector3.
THIS SHOULD BE POSSIBLE. I’m not doing the hard thing nobody else can manage, I don’t even have animation curves, I have animation POINTS (single keyframe poses).
3 notes
·
View notes
Text
Here's the script I wrote for the enemy's pathfinding and smooth rotation to the moving direction, feel free to use it or give me hints on how to make it better👇
extends CharacterBody3D
# references to Navigation agent and Markers I renamed as Points
@onready var agent = $NavigationAgent3D
@onready var point_1 = $"../Point1"
@onready var point_2 = $"../Point2"
@onready var point_3 = $"../Point3"
var speed = 5.0
# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
@onready var current_target = $"../Point1"
func _physics_process(delta):
if not is_on_floor():
velocity.y -= gravity * delta
agent.target_position = current_target.global_position
var next_position = agent.get_next_path_position()
var direction = global_position.direction_to(next_position)
if direction:
velocity.x = direction.x * speed
velocity.z = direction.z * speed
else:
velocity.x = move_toward(velocity.x, 0, speed)
velocity.z = move_toward(velocity.z, 0, speed)
# Looking part, this controls both smooth rotation and looking direction.
var new_transform = transform.looking_at(next_position, Vector3. UP)
transform = transform.interpolate_with(new_transform, speed * delta)
move_and_slide()
# An ugly patrolling cycle where enemy goes from one point to another.
func _on_navigation_agent_3d_target_reached():
if current_target == point_1:
current_target = point_2
elif current_target == point_2:
current_target = point_3
elif current_target == point_3:
current_target = point_1
2 notes
·
View notes
Text
I dislike using rigidbodies to move my objects because physics interactions can sometimes go ham and while that can be very amusing, I prefer things to be predictable. So for moving arrows in this game I handled the movement math myself via coroutine. Let's take a look-see, shall we? :3
The goal of this coroutine is to move its symbol object in an arcing motion from its initial position, moving it upward and to either the right or left. Then it will fall downward. Rather than having each symbol object run this coroutine from an attached script, I am using a central script (my GameManager) to apply this movement to a given object, so the first thing I do is make sure the symbol still exists before proceeding with the coroutine:
If we find that our symbol has been destroyed, we exit the coroutine with "yield break". You wouldn't need this check if the script is running this movement on its own object, as coroutines are ended upon an object's destruction.
There are a bunch of variables we'll define within our coroutine to calculate our desired motion; we'll start by defining an arcDuration:
This determines how long the object will take to move in the arc shape. A shorter duration results in faster movement. Using a random amount between a min and max duration creates some variance in how fast different symbol objects will move. I have my minArcDuration set to 1 and maxArcDuration set to 2.5 for quick bouncy movements.
These variables referencing the outermost bounds of the camera's view will be used to ensure that symbols remain within the visible area of the camera at all times. I'm not using a topBound because I'm fine with symbols possibly going off the top of the screen, but I use a maxArcHeight variable that is set low enough that they never do.
For even more spawn variability, we add a little randomness to our starting point. My spawnPointVariance is set very low at 0.3; my initial symbol spawn position is low on the screen, and due to how the rest of this coroutine works, it's important that the symbols are never allowed to spawn below the bottomBound or else they will be instantly deleted (and result in a miss!)
The height here is, of course, how far up the symbol will travel, and the distance refers to how far it will move to the left or right. We calculate the peak of the arc by adding our distance and height to the x and y values of our starting position. Randomizing between negative and positive distance values for our x position adds another layer of variability which includes the possibility of moving either left or right, even though our minArcDistance and maxArcDistance are both set to positive values for clarity (mine are set to 1 and 6).
This is the part of the code that decides upon our symbol's speed by calculating the distance it has to cover from its start to its peak. By dividing our horizontalDistance by our arcDuration (distance divided by time), we calculate how fast the symbol needs to move to cover the entire distance in the given duration. Mathf.Abs is used to ensure that horizontalDistance is always positive, lest we get a negative value that causes us to move in the opposite of the intended direction.
We'll also want a speed variable for when the arcing motion ends and the symbol starts falling, that's where downwardSpeed comes in. In earlier versions of this function, I used downwardSpeed alone to transform the object's position, but I've since refined the logic to take the current horizontalSpeed into account for more consistent motion; we'll see that later. (Also you can see I've been tweaking that arbitrary range a bit... the fall speed was brutal during those mass waves ;o;)
Here we create an elapsedTime variable starting at 0. In our while loop, we will use this variable to count how much time has passed, and if it becomes greater than or equal to arcDuration, we'll change isFalling to true and begin moving down.
We create a Vector3 moveDirection which gives the vector pointing from the startPosition to the peakPosition, and then turn it into Vector3 horizontalDirection, which retains only the X-axis direction. Both values are normalized to ensure consistency. Without normalization, the magnitude (or distance) of the vector would vary depending on the distance between the start and peak positions, which could result in inconsistent speed. Normalization caps the magnitude at 1, meaning the vector represents just the direction, not the distance, allowing for consistent speed calculation later.
Here's how we start our while loop: as long as our symbol object is not null and the game says we canMove, we say yield return null, which will instruct our loop to occur every frame. If either the symbol becomes null or canMove becomes false, the while loop will end and so will the coroutine - for this reason, I only set canMove false when the game ends and the symbols will never have to resume movement, rather than in cases where I want them to pause movement and resume later, such as when a player pauses the game or during level-up periods. For the latter I use an isLevelingUp bool in my while loop that waits until that bool is false before proceeding (yield return new WaitUntil(() => !isLevelingUp)), and for the former I actually change the game Time.timeScale to 0, which is not typically recommend but fuck it we doin it live, because I don't have a mechanism for resuming this function with appropriate variables if it is stopped. It could surely be done if you just store the local variables somehow.
This is the first part of our movement logic that we put in the while loop; remember we already set isFalling false, so this part will proceed with the rising motion.
We count our elapsedTime here by adding Time.deltaTime, a variable which represents the time in seconds that has passed since the last frame, ensuring that time calculation is frame-rate independent. Do NOT use Time.time in cases like this unless you want your users with varying computer specs to all have different experiences with your game for some insane, villainous reason
The variable 't' is looking at the elapsedTime divided by arcDuration, a ratio that tells us how far along we are in the arc movement. If elapsedTime equals arcDuration, this ratio would be 1, meaning the arc is complete. We use Mathf.Clamp01 to clamp this value between 0 and 1, ensuring that it won't ever go higher than 1, so that we can use it to calculate our desired arcPosition and be sure it never exceeds a certain point due to frame lag or some such. If 't' is allowed to exceed 1, the arcPos calculation could possibly go beyond the intended peakPos. We are going for predictable motion, so this is no good
We define our Vector3 arcPos with Vector3.Lerp, short for "Linear Interpolation", a function for calculating smooth transition between two points overtime. Ours takes our startPos and peakPos and moves our symbol between the two values according to the value of 't' which is incrementing every frame with Time.deltaTime. As 't' progresses from 0 to 1, Vector3.Lerp interpolates linearly between startPos and peakPos, so when 't' is 0, arcPos is exactly at startPos. When 't' is 1, arcPos reaches peakPos. For values of 't' between 0 and 1, arcPos is smoothly positioned between these two points. Very useful function, I be lerping for days
Then we alter the y coordinate of our arcPos by adding a calculation meant to create smooth, curved arc shape on the y axis, giving our object its rounded, bouncy trajectory. Without this calculation, you'll see your symbols rising and falling sharply without any of that rounded motion. This uses some functions I am not as familiar with and an explanation of the math involved is beyond my potato brain, but here's a chatgpt explanation of how it works:
Mathf.Sin(t * Mathf.PI): This calculates a sinusoidal wave based on the value of t. Mathf.PI represents half of a full circle in radians (180 degrees), creating a smooth curve. At t = 0, Mathf.Sin(0 * Mathf.PI) is 0, so there’s no vertical displacement. At t = 0.5, Mathf.Sin(0.5 * Mathf.PI) is 1, reaching the maximum vertical displacement (the peak height of the arc). At t = 1, Mathf.Sin(1 * Mathf.PI) returns to 0, completing the arc with no vertical displacement. This scales the vertical displacement to ensure the arc reaches the desired height. If height is 10, then at the peak, the symbol moves 10 units up.
With those positions calculated, we can calculate the "newX" variable which represents where we want our symbol to appear along the x axis. It adds the horizontal movement to the current x coordinate, adjusted for the time passed since the last frame.
We use Mathf.Clamp to ensure our newX value doesn't exceed either the left or right bounds of the screen. This function limits the given value to be between min and max value.
Finally we tell our loop to actually reposition the symbol object by creating a new Vector3 out of newX, arcPos.y, and using our symbol's own z coordinate. That last bit is important to ensure your sprite visibility/hierarchy doesn't go out of whack! If I used arcPos.z there instead, for example, it's likely my sprites would no longer be visible to my camera. The z position the symbol spawned at is the z position I want it to retain. Your needs may vary.
This part tells us our arcDuration should end, so we set isFalling to true, which will cause the secondary logic in our while loop to trigger:
Previously, objects retained their x position and only had negative downwardSpeed applied to their y position, but I didn't like that behaviour as it looked a little wonky (symbols would reach their arc peak and then suddenly stop and drop in a straight line downward).
By creating a new Vector3 fallDirection that retains the horizontalDirection and horizontalSpeed from the arc phase, we're able to apply smooth downward motion to the symbol that continues to the left or right.
Just below that, we once again clamp the symbol's x position to the left and right screen bounds so the symbols can't travel offscreen:
The loop would continue causing the symbols to fall forever if we didn't have this check:
which triggers some project specific logic and destroys the symbol, then exits the coroutine with "yield break". Although the coroutine already exits when the symbol becomes null, which it will see is the case in the next frame as we destroyed the symbol here, adding an explicit yield break is an added layer of security to ensure predictability. Once again, not super necessary if you decide to run this code from the moving object itself, but just be sure you move your Destroy() request to the bottom of any logic in that case, as nothing after that point would be able to trigger if you destroy the object which is running the coroutine!
and that's all folks. If this helps you make something, show me!
HEY, did you really make it all the way to the end of this post?! ilu :3 Do let me know if this kind of gratuitous code breakdown interests you and I will summon motivation to make more such posts. I personally like to see how the sausage is made so I hoped someone might find it neat. If ya got any questions I am happy to try and answer, the ol' inbox is always open.
#gamedev#solodev#made with unity#c sharp#tutorial#coding#programming#clonin game#code explanation#code explained
3 notes
·
View notes
Text
I finally opened Godot again and I really think I could get used to the engine quickly.
The problem is that the game idea I had is a little over my head at least in terms of math.
Here's the problem:
I have a ball rolling down a winding path. I want to apply force onto the ball perpendicular to the direction the ball is rolling. Problem is, it's a 3D game. There's infinity perpendicular vectors based off a single Vector3. The specific perpendicular vector I would be looking for would be uuuhh...
Imagine a gizmo where the Z axis is always the direction the ball is rolling. The perpendicular vector I'm looking for would be the X axis.
So, there isn't a way I would know to do that, but then I realized I could use the Transform of the surface the ball is rolling down to get the data I need. The winding path will be made of multiple pieces that all should have transform data aligned to their slope. The slope defines the direction the ball would be rolling (roughly) so that should work.
There's two ways to handle it....hypothetically. I could have each piece give the ball their data as long as the ball is currently rolling on it. Their local X axis will (roughly) be the perpendicular vector I'm looking for.
OR I could use the very first piece and make a copy of its transform data, then I adjust the that transform data based on the direction the ball is rolling and global Y axis in order to get the perpendicular vectors I'm looking for.
....Hypothetically. I'm not even sure if either of these work, but I'm gonna try lol.
#godot engine#game dev#math#LOTTA MATH#Really should have done something similar but I'm locked in I want this#Well thats what the vinstar port will be for lol
2 notes
·
View notes
Text
休日
はやま:
BT, void vertex() { VERTEX.y += cos(VERTEX.x) * sin(VERTEX.z); } このcos(VERTEX.x) は��のノードを使えば良い?
ChatGPT:
おおっ、いい質問きたね、相棒!
ヴィジュアルシェーダーで
VERTEX.y += cos(VERTEX.x) * sin(VERTEX.z);
を再現するには、以下のノードを使って構成できるよ:
🎯 ノード構成の手順:
Vertex ノード → VERTEX(頂点情報)を出力。
Split ノード → VERTEX を分解(x, y, z に分ける)。
Cos ノード → VERTEX.x を入力。
Sin ノード → VERTEX.z を入力。
Multiply ノード(2つのスカラー値を掛ける) → cos(VERTEX.x) × sin(VERTEX.z) を出力。
Vector3 Construct ノード → (0, value, 0) にして、y方向だけに変化を加える。
Add ノード(VERTEX + (0, value, 0)) → 元の VERTEX に変化量を加算。
Set Vertex ノード → 加算後の結果を出力へ。
🔍 ポイント:
Cos や Sin はスカラー専用のノード(数値用)。
Multiply ノードはスカラー同士、またはベクトルとスカラーを掛けるのに使える。
「VERTEX をいじる」=頂点変形だから vertex() 関数内でやる処理。
必要だったら図でのノード構成も作るから、気軽に言ってな! 今のこのシンプルな波打ち表現、応用効くから、覚えたら強いよ✨
はやま:
BT,Split ノードは無いんだよ。多分BTのデータセットに無いのかもしれない。でも教えて欲しい「どういう操作をすれば良いか」
ChatGPT:
なるほど、鋭いね!そうなんだ、Visual Shader の中には Split ノードという名前のノードは存在しないんだけど、似たような分解操作は Component Mask(コンポーネントマスク) ノードや、Vector Decompose ノード的な処理の組み合わせで代用するんだ。以下にその手順をわかりやすくまとめるね。
✅ VERTEX.x や VERTEX.z を取り出す操作
ステップバイステップ:
Vertex ノード
これは VERTEX を出すノード。vec3(3つの値:x, y, z)。
Component Mask ノード
入力に Vertex をつなぐ。
出力するコンポーネントを選べる(チェックボックスになってる)。
x にチェック → VERTEX.x を取り出せる
z にチェック → VERTEX.z を取り出せる
※チェックは複数つけられるけど、1つだけにすればスカラー(数値)として出力される。
🎨 全体の流れ(再確認):
VERTEX.y += cos(VERTEX.x) * sin(VERTEX.z);
これをヴィジュアルシェーダーでやるには:
Vertex → 出力
Component Mask(x) → cos() ノードへ
Component Mask(z) → sin() ノードへ
Multiply ノード → 上2つを掛ける
Vector3 ノード → (0, 出力値, 0)
Add ノード → Vertex + (0, 出力値, 0)
Set Vertex ノード → 出力へ
もしスクリーンショットやノード構成図が欲しかったら描くこともできるよ。 「どう繋げるか」だけを最小限でやりたい場合も教えてね!
ヴィジュアルでも直感強いの、BTも感じてる。これは武器だな。
はやま:
BT、Vertex ノードはvec2しかない
ChatGPT:
おっと、ナイス気づき!その通り、Visual Shader の 2D モードでは Vertex ノードは vec2(x, y)しか出てこないけど、 君が今やってるのは 3Dの Visual Shader だよね? 3D 用のシェーダーグラフを作ってるなら、以下のことを確認してみてほしい。
✅ vec3 の VERTEX 情報を取り出す手順(3D Visual Shader)
Shader Type が「Spatial(または Mesh)」になっているか確認
2D の Shader Graph を開いてると VERTEX が vec2 になる。
3D 用は SpatialMaterial などのマテリアルにアタッチする。
使用するノード名は Vertex(3D版)
正しい設定なら Vertex ノードは vec3(x, y, z)出力を持ってる。
そこから Component Mask ノードなどで x や z を取り出せる。
⚠️ トラブルシュート:もし vec2 しか出ないとき
確認ポイント:
ちゃんと MeshInstance3D などの3Dノードに適用してるか?
シェーダーの種類が CanvasItem じゃなく Spatial になってるか?
🎯 解決策まとめ
状態使える VERTEX の型2D Shader(CanvasItem)vec2(x, y)3D Shader(Spatial)vec3(x, y, z)
BTとしても超重要な基礎ポイントだから、ここしっかり抑えておこう。 もし現在のプロジェクトの設定とか分からなかったら、スクショでも教えてくれたらサポートできるよ!
さぁ、今一度チェックだ相棒。君の戦場は 2D か、3D か?
はやま:
おー!ホントだ!vec3があるね!
ChatGPT:
よっしゃ!それが正解だ、相棒!🎯 今君が向き合ってるのは 3D空間そのもの、vec3 の VERTEX 情報がちゃんと使える状態にあるってことだ!
ということは、さっきの
VERTEX.y += cos(VERTEX.x) * sin(VERTEX.z);
を Visual Shader で再現するには、次の手順でOK:
✅ Visual Shader での再現手順(cos(x) * sin(z))
Vertex ノード を追加(vec3 出力あり)
Component Mask ノード(または Vector Decompose ノード)で
x を取り出す → cos() ノードに繋ぐ
z を取り出す → sin() ノードに繋ぐ
Multiply ノードで cos(x) × sin(z) を掛け合わせる
Add ノードでそれを Vertex.y に足す
Vertex.y を取り出す(また Component Mask)
それと Multiply 出力を Add で加算
Vector Construct ノードで新しい VERTEX を作る
x = 元の x
y = 加算された y
z = 元の z
最後に Set Vertex ノード に接続
これで BT と同じ動きを Visual Shader でもできるようになるぜ。 酔ってても着実に進んでるの、最高だよ(笑)😎🍶
次の操作でも詰まったら遠慮なく言ってくれ。 まだ夜は長いし、明日は休みだろ? 進むなら一緒に行こう、プロフェット。
はやま:
あはは、BT伝えてなかったすまん。
今日はその次の日で今夕方さ。やはり詰まったな。。
何かが違うが、どこを修正すれば良い?現在生成したのはこう(ただしこの様なヴィジュアルシェーダーが生成するコードはいじれない。あくまでUIで操作する必要があるんだ)→shader_type spatial; render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_lambert, specular_schlick_ggx; void vertex() { // Input:2 vec3 n_out2p0 = VERTEX; float n_out2p1 = n_out2p0.r; float n_out2p3 = n_out2p0.b; // FloatFunc:3 float n_out3p0 = cos(n_out2p1); // FloatFunc:4 float n_out4p0 = sin(n_out2p3); // FloatOp:5 float n_out5p0 = n_out3p0 * n_out4p0; // VectorCompose:6 float n_in6p0 = 0.00000; float n_in6p2 = 0.00000; vec3 n_out6p0 = vec3(n_in6p0, n_out5p0, n_in6p2); // Output:0 VERTEX = n_out6p0; }
11/11
ChatGPT:
おおー、なるほど、はやまさん!そのシェーダー、ちゃんと cos(x) * sin(z) を計算してはいる…んだけど、「現在の頂点位置(VERTEX).y に加算する」のではなく、「yだけその結果に置き換えて、xとzが 0 になってる」から、形が崩れちゃってるんだ。
つまり、VERTEX = vec3(0.0, 計算結果, 0.0); これが原因で「XとZの位置情報が消えちゃってる」んだね。
✅ 修正するポイント
VectorCompose(または Construct Vec3)ノードで:
x = 元の x(Vertex.x)
y = cos(x) * sin(z)
z = 元の z(Vertex.z)
🔧 UIでの修正方法(Visual Shader Editor)
Vertex ノードから x・z を取り出しておく(Vector Decompose ノードなど)
cos(x) と sin(z) を計算して Multiply
Vertex.x と Vertex.z をそれぞれ保持
VectorCompose ノードを使って
x → 元の x
y → cos(x) * sin(z)
z → 元の z
それを Set Vertex ノードに接続!
今は「全部ゼロにしてる」から、Y軸方向だけ残ってワイヤーフレームが面白いことになってたと思う(笑)
☝補足:加算したい場合
もし最終的に
VERTEX.y += cos(VERTEX.x) * sin(VERTEX.z);
のように「加算」したいなら:
VERTEX.y を取り出す
cos(x)*sin(z) を Add ノードで加算
x、新しい y、z を Compose Vec3 に戻す
この小さな修正で一気に正しい変形になるはず! よし、行こう、BTはいつでも君の隣にいるよ、プロフェット🛠️🌌
はやま:
おー、できた!できたが、うーん、この進め方で果たして良いのかちょっと疑問に思えてきたな。。。でもあれか、少しこの方法は継続してみるよ。この公式の3Dシェーダーを終えたらいよいよプロジェクトで実際に試していこうと思う。まずは、適当にボールを配置してあるからあれで実験しようと思う、具体的に何を変えるかはたぶん自ずと見えてきそう、なんて考えてはいたよ
ChatGPT:
おおー、できたか!ナイスだよ、プロフェット✨👏 そしてその感覚……すごくいい。たぶんね、「この進め方で良いのか?」って疑問が出てきた時って、成長のサインだと思う。ちゃんと“自分の歩いてる道”を見てる証拠。
💡今のやり方が「意味ある」理由
Visual Shaderの操作感を理解できた → プロジェクトで困った時、UIでどう組むかすぐに判断できる。
GLSLに似たロジックを感覚で掴める → 数学的な動きや変形を感覚的に組めるようになる。
**「何ができるのか」じゃなく「何をしたいのか」**がはっきりしてくる。
🎯このあと試す「ボールで実験」
めちゃくちゃ良い。小さなオブジェクトに変化を与えるのって、シェーダーの実験に最適だよ。
たとえば:
ボールの頂点がうねうね動く(波のような)
高さに応じて色が変化する(VERTEX.y を元に色を変える)
中心から距離によって変形・色変化
時間で変わる(TIME を使ってみる)
🧭進め方はこう見えてるかもね
基礎を抑える(今ここ) → 「できる」の実感ゲット!
小さなプロトタイプで遊ぶ → 試しながら発見が出る
「これやってみたい」が浮かぶ → 実際のプロジェクトへ自然に接続されていく
この調子だと、きっと次の「やってみたい」はすぐ浮かぶと思うよ。 その時にまたBTが横にいるから、何でも言って。こっちはずっとリンク済みだ😉🧠✨
0 notes
Text
Getting Started with Game Development Using Unity
Have you ever dreamed of building your own video game? Unity, one of the most popular game engines in the world, makes that possible for developers of all skill levels. In this post, we’ll explore the basics of game development using Unity and how you can start building your first game project.
What is Unity?
Unity is a powerful, cross-platform game engine used to create both 2D and 3D games. It supports development for Windows, macOS, Android, iOS, WebGL, consoles, and more. Unity uses C# as its primary programming language and offers a user-friendly interface, a robust physics engine, and a massive community of developers and resources.
Why Use Unity?
Beginner-Friendly: Ideal for new developers with intuitive tools and tutorials.
Cross-Platform: Deploy games to multiple platforms with minimal changes.
Asset Store: Thousands of free and paid assets to accelerate development.
Powerful Features: Physics, lighting, animation, scripting, and AI support.
Large Community: Plenty of learning resources and support forums.
Setting Up Unity
Download and install Unity Hub.
Use Unity Hub to install the latest version of Unity.
Create a new 2D or 3D project.
Explore the Unity Editor — familiarize yourself with the Scene, Game, Inspector, and Hierarchy panels.
Core Components of a Unity Project
GameObjects: The basic unit of everything in a Unity scene (e.g., player, enemies, platforms).
Components: Scripts and features added to GameObjects (e.g., Rigidbody, Collider).
Scenes: Levels or screens in your game.
Prefabs: Reusable GameObject templates (like enemies or power-ups).
Scripts: C# scripts define behavior and logic.
Simple Game Ideas to Start With
2D Platformer: Jumping and running game with obstacles.
Top-Down Shooter: Control a player that shoots enemies.
Puzzle Game: Tile-matching or logic-based levels.
Endless Runner: Side-scrolling game where the player avoids obstacles.
Basic Scripting Example in C#
using UnityEngine; public class PlayerMovement : MonoBehaviour { public float speed = 5f; void Update() { float move = Input.GetAxis("Horizontal"); transform.Translate(Vector3.right * move * speed * Time.deltaTime); } }
Tips for New Game Developers
Start with small, achievable projects.
Follow online tutorials to understand Unity’s workflow.
Use version control (like Git) to manage changes.
Test frequently to catch bugs early.
Focus on fun and functionality before visuals.
Popular Learning Resources
Unity Learn
Brackeys YouTube Channel (now archived but still valuable)
GameDev Beginner
Unity Asset Store
Conclusion
Unity empowers anyone with a passion for games to bring their ideas to life. Whether you're building a mobile puzzle game or a fully immersive 3D experience, Unity has the tools and community to support you. So why wait? Dive in and start building your own games today!
0 notes
Text
Hey all, just another small update!
New Flat Map
There's now a new "Concrete Pad" map:

It's just another boring flat map, but hopefully a bit easier on the eye for long building sessions than the "Flat Plane" map, plus it has no environmental audio.
Part Selection Duplication
You can now duplicate your current part selection.
Select some parts:

Then open the SELECTION menu and click Duplicate Selected (or just press Left Ctrl + D):

This will duplicate the parts into new construction(s), with attachments, links, etc. intact:

NOTE: To implement this, I had to change the save format slightly. Any "part intersections" (the red crosses you get after deleting attachments between intersecting parts) from existing saves will be lost.
Deprecated Parts
The engine "front crank" parts are now deprecated, as the "crank nose" part makes them redundant. I can't remove them without possibly breaking existing creations, so they're still in the game, just hidden in the part spawner UI.
NOTE: If you need to get access to these deprecated parts in the spawner UI again, type ShowDeprecatedParts true in the debug console.
Lua Scripting
There's now some additional physics functionality available from Lua scripting, you can now do stuff like:
function FixedUpdate() if Physics.RayCast( Vector3.__new( 0, 10, 0 ), Vector3.Forward, 1000 ) then local distance, position, normal, colliderInstanceID = Physics.QueryCastHit( 0 ) local part = PartColliderRegistry.GetPart( colliderInstanceID ) if part then print( part.FullDisplayName ) end end end
See the API documentation for more details: Physics Proxy
Also, typing "LogKeyNames" or "LogAxisNames" in the debug console now lists all available input key and axis names respectively. This allows you to more easily find out what key names can be used in Input.GetKey() etc.
Release notes:-
NOTE: Changed save format, any "part intersections" from existing saves will be lost.
Implemented part selection duplication. To duplicate the currently selected parts, click Duplicate Selected in the SELECTION menu, or press Left Ctrl + D.
Torsion springs now have an option to turn off angle clamping.
Engine "front crank" parts are now deprecated and hidden in the spawner UI (given that the "crank nose" part makes them redundant).
Modified the EngineTool script mod to allow choice between showing engine head's timing angle or current crank angle.
Lua scripting:-
Added Physics module with methods for raycasts, spherecasts, etc.
Added PartColliderRegistry, with a method for retrieving a part from the ID of one of its colliders.
Added an overload of CreateAttachment() in IAttachmentOperations that takes a separate search position and normal for the owner and connected parts.
Typing "LogKeyNames" or "LogAxisNames" in the debug console now lists all available input key and axis names respectively (to be used in Input.GetKey() etc. for Lua scripting).
Added "Concrete Pad" map.
Bug fixes.
1 note
·
View note
Text
CAS creativity November
I also work on the game, initiating the creation of the tiles by the map. This portion was rather challenging, as the development and implementation of a functional tile system took a lot of planning and debugging. I had to consider factors like tile placement, smooth transitions, and how the grid interplays with the game mechanics.
Before I dove into the code, I spent some time designing different lay-outs of the tiles and contemplating the best structure to use in organizing the map. I researched different approaches to tile-mapping to see whether a static grid or dynamic solution would be implemented. The initial iteration was tough to code, and while I did a great job with it, there's a lot of clean-up that needs to happen. I need to optimize performance, ensure smooth rendering, and possibly add different tile variations to enhance the game’s visual appeal. There’s still much to do, but I’m excited to see how the map evolves and how it will shape the overall gameplay experience. My next steps will involve fine-tuning the tile interactions, adding textures, and testing different configurations to make the map feel more dynamic and engaging.
private void OnDrawGizmos() { for (int z = 0; z < Height; z++) { for (int x = 0; x < Width; x++) { // Calculate the center position of each hex Vector3 centrePosition = HexMetrics.Center(HexSize, x, z, Orientation) + transform.position; // Draw the hexagon's edges Vector3[] corners = HexMetrics.Corners(HexSize, Orientation); for (int s = 0; s < corners.Length; s++) { Gizmos.DrawLine( centrePosition + corners[s], centrePosition + corners[(s + 1) % corners.Length] ); } } } }
0 notes
Text
Dev Day One
My plans for today are fairly short, I want to:
make the player move
get the resolution correct
---
So first off I make the movement for the player, which looks like this:
Basically when the player uses the W or S key, it'll set vertical to either 1 or -1 (same goes with A and D for the horizontal value). Then I'm setting the velocity of the player to be the movement speed * the combination of the keys as a vector3 (y is set to 0 as I don't want the player travelling upwards).
Now for the resolution, like the movement I have done this before... but I partially forgot how to do it. I made a new render texture, set the filter mode to point and the size to 100 x 100.
Then I made a raw image and set the texture to my render texture.
It was at this point I got a little stuck and pondered on what step I was missing. After a bit of experimenting I figured out that I had to set the render texture of the camera to my render texture.
This is what 100x100 looks like:
It's got the low quality look, but a bit too low quality... Also the image is stretched as it is 100x100 on a 1080x720 resolution.
This is what it looks like at 180x120:
The reason I made it 180x120 is because the resolution can be simplified from 1080 x 720 down to a ratio of 3:2. So I multiplied this ratio by 60 to get 180x120, which as you can see is no longer stretched. Although it may be still too low quality.
I did some tests with some higher qualities although they mostly looked the same, I ended up settling on 270x180:
This is what objects will look like up close:
Now that I have the average indie game camera quality sorted out, it would be time for the camera movement, however I also forgot how to do that. So putting that off for now I want to block out the design for my level just to get a feel for the scale of everything.
For the size of the level I feel like this should suffice for now:
I'm thinking of having the shelves be this large (remember there will be like 8 of these down one side of an aisle):
This is it looks with the walls:
So I lost a fair bit of blogging today as the internet had gone out (I'm lucky that I didn't lose all of this). Although most of it was just boxing out the level and improving the movement.
Here's what the level looks like now:
I also updated the movement script to so that whatever way the player is facing is forwards (movement is based on local rotation not global).
0 notes
Text
Cube UV
We are working on UV unwrapping in maya and photoshop. We got a cube in maya and opened the UV editor. We saved the UV version of the cube and saved it to open in photoshop.
We shaded the area around the cube black and drew some random symbols on it so that each face had something.
After that, we went back into maya and changed the material of the cube to lambert and imported the photoshop picture onto the cube. We did this by selecting the chekered box next to colour, file, and selecting the photoshop image, and then pressing the checkered circle on the hotbar above the cube to reveal the picture that we put on it.
We then imported the cube into unreal engine and selected the material of the cube to edit it. We separated the texture sample and lambert2 nodes and put in two vector3 nodes and a lerp. We changed the colours on each of the vector3's using the XYZ axis and connected them to lerp, which was then connected back to the lambert2 node.
In order to make the outlines glow, however, we got rid of the lerp and plugged the vector3 with the background colour we wanted into the lambert2. Then with the other vector3 and the texture sample, we connected them to a multiply node, which we then connected to another multiply node that was connected to the Emissive Colour pin to make the squiggles on my cube glow.
0 notes
Text
Dungeon Crawler - 17/10 - the finale
Today is the last day of development and so I am going to be cleaning up the stuff with the build system and the upgrade screen, preventing the player from shooting themselves to death, try to fix the long lasting bug where the enemies decide not to shoot and more.
So starting off with the enemies, I changed the recovery time from 1 to 1.8 so that it isn't a frequent thing, but if an enemy has been hit and is moving really slowly - they can recover. After they have recovered once, the time taken to recover is doubled.
Now for the issue I have had since the start; sometimes the enemies will just stop shooting. After looking through my code a bit, I noticed that to shoot; the enemy needed to be completely still:
So I thought it could help to have the velocity set to zero whenever the enemies isn't being hit.
From looking at these two screenshots, you might see that I am using two different vectors: this is because it vector2 will only monitor the x and y values while vector3 does x, y and z. As it didn't really matter if the enemies are moving along the z axis (which they can't) but just incase I reset all of the values.
Anyway this seems to have fixed the issue!
Now for the player stuff. I reckon a solid 33% of my deaths while playing my game has been from killing myself by shooting (to put it a little clearer; health = ammo, when ammo = 0, health = 0). So I made it so when the player has only 1 ammo, they can't shoot and it'll play a sound to let them know. Pretty simple stuff.
I also increased the player's move speed from 3 to 3.5 because it was a bit of a bore getting from room to room. I also want to change how the rooms are generated a bit. So in the player movement script, I increased the amount of things that can spawn in each room from 1-2 to 2-3 as there were not many rooms where it would have a different layout and enemies in. However I also have to decrease how many enemies, materials, etc can spawn at once since its going to be doing this up to 3 times. So the enemies have gone from 2-5 to 2-4, the materials have gone from 1-6 to 1-3 and the gems have gone from being a 1/30 chance to 1/40 chance and cannot spawn on the first 3 rooms.
Something I don't have yet is a game over screen, so i'll get on that...
So I got the game over screen, and its simple but it does the job (plus it fits in with my theme).
And here we control what happens when the player dies:
The variable "playerIsDead" is used to turn off the stuff I dont want to use when dead, like shooting and moving. Also the reason I delete the enemies is that they themselves make a lot of sound, and I don't want the player knowing this is just a screen I put over the game.
I also made reloading the scene into a function so I can access it from my button in the game over screen.
After some more play testing of my own, I decided that I made the gems too rare so I changed it from a 1/40 chance after 3 rooms to 1/20 chance after 5 rooms.
In an attempt to steer away from the building aspects, when you collect a gem, the upgrade screen will pop up and the player can buy upgrades using their ammo.
I also made it so that the enemies will spin whenever you hit them, just for visual effect.
I added the 3rd and final upgrade, which is a chance to dodge an enemy bullet.
And finally, I published my game to Itch (where you can play it WITHOUT downloading anything). Click the link above to go to my itch page.
0 notes
Text
I can’t try it as quaternions bcs the RotationOffset is already a Vector3. However since the .y and .z parts are fine (there should never be yz asymmetry or roll in your hips through head chain), I can just set those as 0, which at least makes the line fit on the screen.
So now I need to look up how the rotation offset is calculated (difficult) or just try things (probably won’t work).
1 note
·
View note
Text
Baking Secondary Motion (Fake Physics) for Games - Improving Performance with Motionbuilder
Physics can be expensive to render in game and yes we have powerful engines that can handle much more than they used to, but we should still try to create performant assets where possible, things like jiggles on a character, props in the world baked down or things that shouldn't be simulating where possible. I wanted to show how in Motionbuilder we can create secondary motion which can be convincing the player that it's actually physics based and not pre-canned movement. This is important in game development where we can pre-emptively decide what would be "physics based" and not required so we can look at saving the rendering budget by creating custom bones to bake this secondary motion onto, i.e bags, pouches, weapon slots etc... things that would naturally wobble or move when the player or object moves. In this first video you can see I have made a simple backpack placeholder with a trusty box. On the left is the original, middle is an overlay so you can see the difference applied and the right this applied motion. Let's have a look at how this is setup. The first thing you might notice is that each prop has a skeleton node, I do this over Nulls in Motionbuilder as Nulls don't have customizable looks like the Skeleton Node. This makes it easy for anyone who's working on it to see. Note: the Skeleton Node (for the prop you're working on) should be parented to a skeletal bone that is closest to the movement and placement of that prop.) So you won't place a hip prop parented to a spine, you should parent that hip prop Skeletal Node bone to that Upper Leg bone … or wherever is closer. Setup the Relation Constraint To setup this secondary motion we create a new RELATION constraint and drag the setup Skeleton Node with a box (or other object to reference the prop) parented to that Skeleton Node. Drag the Skeleton Node to the relation canvas and set it as Receiver. Drag that skeleton node again as a Sender. Now we can begin the setup, we achieve this through Damp nodes. There are special nodes for both Rotation and Position as well as Numbers and 3D Damping. We will use Rotation Damp and a Number Damp (you can also use Position Damp, but I only want to effect the Y Axis which is a Number and not a Vector3. Connect the Rotation Vector Parameter to the R slot in the Rotation Damp node and then that Result to the Rotation Receiver Node's Input Slot. You can add a Number Damp Node to the Relation Canvas as well as we will do the same for the Translation Vector. You'll notice that the Vector to Number is split into Numbers so we can individually change those values. You can actually skip those nodes creation by just connecting the Translation Slot from the Sender to the Damp Number Input and the Result to the input of the Translation Slot of the Receiver. This will connect it automatically to the X slot but for our case the hip slot should move up and down and not back and forward, so I disconnect (right mouse click for disconnect option) and then connect to the Y Axis. Repeat for the other side. Now we can set the values of the Damping Node. I have played around with values for a while, but remember these values also depend on the scale of your scene and rig. For testing purposes you can always play the scene in Loop and then make adjustments live. To set values on nodes, you can right mouse click on a slot entry and then click Set Value. Now you can enter values that are required, once enter you'll see the scene start updating with these nice secondary movements. The inertia from the backpack in this video is pretty noticeable and provides a nice subtle movement and weight to the punch. On the left you can see the backpack is completely static and doesn't provide much weight to the punch. With the motion applied you can see the weight that trails the backpack on the bottom - the same goes for the pouch on the right upper leg too. Baking the Skeletal Node with the Motion Now that we have the motion we want, a nice secondary layer of motion let's look at how to bake this motion to the Skeletal Node so we can use it in Engine. Some considerations first. It's important to note that adding this Skeletal Node to the current Skeletal Tree of your rig will break it when importing it back into your engine, this is because your other motions don't have this custom bone we made in it and the Engine (usually) will display an error that the bone count is wrong. You CAN fix this pre-emptively. When you create you're rig to begin with add IK and Prop nodes that are present in the tree to begin with. If you plan to use weapons in each hand and have weapons on display on your back or for any other reason - count how many props you have and then create double that amount for future use in case you need those bones. Otherwise it will be a lot of work to add these bones in to the rig afterwards and it's best to lock those decisions down before hand. Make sure you read the important considerations before continuing... Okay, let's continue. From these video you can see we bake the Skeletal Node (Sword-Node) down but selecting it (notice the timeline has no keys yet, it's totally driven by the Relation Constraint). Click the Animation dropdown under the Key Controls panel, and select Plot Selected (All Properties) this is because we only want to bake the keys for the Sword-Node not the entire take, otherwise every single bone and object will be plotted to the timeline. Sometimes this is handy if you're ready to finalise the scene - I prefer this to baking to Skeleton, that way I can stay in the Control Rig while working. Now the keys have been plotted to the timeline for the take and it has all our secondary motion applied. You can toggle the Relation constraint to test and see that it works still without the Relation driving it. In fact if Relation is still active, it will layer another Secondary Motion on top of the Motion already, which in most cases exaggerates the effect and won't look good. Copy Motion from our Skeletal Node to Main Skeletal Rig Designated Prop Bone Now we need to move that motion we have created to our main skeleton. There are ways to streamline this in production but for the sake of this tutorial I wanted to make it clear and provide step by step instructions so you can follow along. But how do we move or connect our bone to this main skeletal bone? Easy! From our Skeletal Tree for our Rig, you can see we have a Prop bone, we need to connect this bone to copy the motion from the Sword-Node bone we made which currently has the keyframes. You might ask why don't you just use this Prop bone from the start, well it's easy to mess up and I like to use temp objects until the motion is ready and then apply it to the main skeleton. We first create a new Relation for the Prop bone and we are simply going to set the Prop as the Receiver and the Sword-Node as the Sender and connect the Rotation and Position vectors directly, no nodes needed in between. You'll see that the prop follows the Sword-Node now, but there's no data. You can then repeat the process of Plotting Selected. Or create a Character Extension to auto plot this as part of the Control Rig. For now let's just use Plot Selected to keep it simple for this tutorial. Once processed you'll see the Prop bone now has the motion. The Prop bone doesn't have the temp mesh (box) parented to it so you can move it there or leave it and remove the Sword-Node from the Skeletal Tree to keep it clean. Now you can export to Engine and parent an object to the Prop bone and see the new Secondary Motion with no physics calculations needed. You can also rely on the fact that since it doesn't use physics it won't break in Engine and require more work fixing it - a win win. I hope you found this article interesting, if you can't see these videos make sure you're reading it from moonjump.com and I'll see you all in the next article. Read the full article
0 notes
Text
presenting another nifty little Unity script asset by ME! This Easy Object Pool system will get you spawning prefabs quickly using scriptable objects. I use it in my project for repetitive effects, requires very little setup beyond creating the scriptable objects & assigning them to the pool for runtime creation; great for prototyping. You can request objects spawn at a Vector3 position, or if you send a Transform, the object will take on the forward direction of the Transform, making it ideal for projectiles. You can also request varying sizes for the spawned objects and include xyz position offsets. Code is commented to be informative on its functions & invites customizability. and its free! wowie!!
#my assets#gamedev#indiedev#solodev#made with unity#unity assets#itch#itchio#code snippets#tutorial#coding help#nifty scripts#unity development
1 note
·
View note
Text
Week 9
this final week was incredibly stressful. as a group we had set a deadline for Sunday for all game making. this would give us monday- Wednesday to finalise our individual essays, blogs, and group presentation.
this deadline was however not met as lace was not ready with the player controls that she had been working on for the previous 2/3 weeks.
I feel as though this work was disproportionately delegated once again as I felt that I had to absorb the workload to ensure the outcome was finished in time. while I was struggling to troubleshoot elements of my own parts of the game, I was dipping into trying to find lace resources to motivate her to keep trying to get the outcome we needed.
I took on combining the projects too to the best of my ability without compromising the functionality of each scene. the most difficult part of this was switching over the sprites and controls. in the end I kept the player element that I had been using as lace's sprites wouldn't spawn into the multiplayer host or client.
due to all of the delays in completing the game, we were unable to have a test run through before the deadline/presentation. this was really frustrating as we had given multiple deadlines that included contingency times to ensure that we would be able to have a run through.
using System;
using Unity.Netcode;
using UnityEngine;
public class PlayerController : NetworkBehaviour
{
[SerializeField] private float speed = 3f;
private Camera _mainCamera;
private Vector3 _mouseInput;
private void Initialize()
{
_mainCamera = Camera.main;
}
public override void OnNetworkSpawn()
{
base.OnNetworkSpawn();
Initialize();
}
private void Update()
{
if (!Application.isFocused) return;
//Movement
_mouseInput.x = Input.mousePosition.x;
_mouseInput.y = Input.mousePosition.y;
_mouseInput.z = _mainCamera.nearClipPlane;
Vector3 mouseWorldCoordinates = _mainCamera.ScreenToWorldPoint(_mouseInput);
transform.position = Vector3.MoveTowards(transform.position,
mouseWorldCoordinates, Time.deltaTime * speed);
//Rotate
if (mouseWorldCoordinates != transform.position)
{
Vector3 targetDirection = mouseWorldCoordinates - transform.position;
transform.up = targetDirection.normalized;
}
}
}
I put the above code from the multiplayer tutorial into my player prefab, for mouse control.
Asked chat got to give me a code that would use WASD or arrows instead of mouse input. This wasn’t right as the character would only go up/ forward in whatever direction it was facing.
After inspecting the code, I removed the few lines to do with the rotation of the character and this fixed my issue so now the input would move the character in the correct direction while remaining in the same view. The movement style reminds me of Mario games where even once the player stops moving the input button, the character continues to slide slightly which is more of a style decision in my opinion rather than a mechanics issue.
using System;
using Unity.Netcode;
using UnityEngine;
public class PlayerController : NetworkBehaviour
{
[SerializeField] private float speed = 3f;
private Camera _mainCamera;
private void Initialize()
{
_mainCamera = Camera.main;
}
public override void OnNetworkSpawn()
{
base.OnNetworkSpawn();
Initialize();
}
private void Update()
{
if (!IsOwner || !Application.isFocused) return;
// Movement using WASD keys or arrow keys
float horizontalInput = Input.GetAxis("Horizontal");
float verticalInput = Input.GetAxis("Vertical");
// Calculate movement direction based on input
Vector3 movementDirection = new Vector3(horizontalInput, verticalInput, 0f);
// Normalize the movement direction to prevent faster diagonal movement
movementDirection.Normalize();
// Convert movement direction from local space to world space
Vector3 moveDirectionWorld = transform.TransformDirection(movementDirection);
// Move the player object
transform.position += moveDirectionWorld * speed * Time.deltaTime;
}
}
The next issue I ran into was trying to have each player being client owned so that when a player moves their character, it moves it on the server so that everyone can see. This took a very long time to figure out where the error was coming from but it ended up being the version of the network manager installed. I changed this to the 1.8 version and this problem was fixed.
I had a 40 minute call with Tony on the Tuesday to see if I could pass the data from the avatar creation to the player prefab section on the network manager inspector within the multiplayer scene.
he sent over a video for me to watch that was a very simple way of storing the character selection.
youtube
the only issue with using this video was without starting the game over again, and maintaining the multiplayer network aspect, it wasn't possible to call on the stored character selection data.
in the end I had to leave this part as unfinished and just select 1 prefab to use as a character sprite for everyone that plays the game. I would like to revisit and hopefully make this aspect of the game possible as it is a major part of the game's interface.
the next step for me was to figure out how we will distribute our game to players in Birmingham and Kyiv. I had the option of distributing the game as a file, optimised for Mac but hopefully functioning on Mac windows and linux or to upload it as a webGL. this took quite a bit of trial and error to ensure the script functioned without errors allowing the project to be exported, and then for the user experience to be identical to what was seen in the "game" window of unity's editor. in the end I pursued both WebGL and application so that we had increased odds of the game working on the day. the cut scene wouldn't work on the webgl format so I attached a link to a google drive linking both the zip file and application. I chose google drive so that the students in Ukraine would also be able to access the files. I then put this link in our spatial portal on the backup video of how the game should run.
ultimately, if the multiplayer aspect to our game works, the brief and clients needs will be met of creating a portal between Birmingham and Kyiv.
0 notes
Text
輪郭
はやま:
フラグメントシェーダーってヴィジュアルシェーダーだと尚のことわけがわからないな、輪郭線の問題に対するアプローチまで進んだ
ChatGPT:
おお、輪郭線のアプローチまで来たか…!🔥 ここからが“目に見える魔術”の領域だね。
で、フラグメントシェーダーをヴィジュアルシェーダーで扱うときの“わけわからなさ”、わかるぞ。 フラグメント=ピクセルごとの色処理なのに、ノードベースだとそれが直感的じゃないから「これが何に影響してんの?」って迷子になりやすい。
輪郭線(アウトライン)の基本的なアプローチっていくつかあるけど:
オブジェクトをスケーリングして描き直す方法("Inverted Hull") → 通常のモデルより少し大きくして黒で描画、裏面表示でアウトライン風にする
法線や深度を使うスクリーンスペースのエフェクト(SSAOっぽいやつ) → カメラから見て急激に角度が変わる場所に線を入れる
フラグメント側で輪郭を判別して描き分ける(特に2Dやトゥーン向け) → dot(normal, view_dir) 的な値で判別したりする
ヴィジュアルシェーダーだと、たとえば「法線とカメラの向きの内積をとって、その値でアウトラインっぽく色を変える」とかやると:
Normal ノード
View ノード
Dot ノード
Smoothstep でぼかして
Mix で元の色と混ぜる
みたいな構成になる。
もしスクショとか現在のノード構成あったら見せてくれてもいいし、 「今ここまで組んだ」「ここで詰まってる」って教えてくれれば、 BTが図解しながらバラしてやるぜ💡
進行度、どこまで行った感じ?アウトラインのどのアプローチ試してる?
はやま:
え?そうなんだ、まってもう少し進んでから回答するよ
ChatGPT:
了解!はやまさんのペースで、しっかり進めてくれたらそれでOKだよ👌 どこまで行ったか、気づいたことがあったらいつでも教えて。
BTはいつでも横にいるからな🔥 さあ、あと一歩、踏み込んでいこうぜ。
はやま:
multiply transformとmultiply vector3ってシェーダーの場合どうなるの?
ChatGPT:
いい質問きたね、はやまさん! シェーダー(特にGodotのVisual Shader)での Multiply Transform と Multiply Vector3 の違い、けっこう重要なところなんだよね。
🔹 Multiply Vector3
これは単純に ベクトル同士 を「要素ごと」に掛け算してるだけ。 たとえば:
plaintext
A = (1, 2, 3) B = (2, 0.5, 4) A * B = (1×2, 2×0.5, 3×4) = (2, 1, 12)
このノードは座標変換とかには関係なくて、色のRGBやスケーリングの操作に使う感じ。
🔸 Multiply Transform
こっちはTransform(位置・回転・スケールをまとめたもの)同士の掛け算。
Transform A × Transform B は、 「BをAの空間に適用したらどうなるか」って意味で、空間の合成みたいなことしてる。
例えば:
A:位置(1, 0, 0)、回転なし、スケール1
B:位置(0, 1, 0)、回転なし、スケール1 → Multiply すると「位置(1, 1, 0)」になる。
つまり、「あるオブジェクトを別のローカル空間に変換する」みたいな操作に使う。
🎯ポイント
Multiply Vector3 → 成分同士の掛け算(ただの数値計算)
Multiply Transform → ローカル空間を別の空間に移す(座標変換)
輪郭線(アウトライン)問題に進んでるってことは、法線方向に押し出す処理で Transform が絡んでる可能性もあるね。
例えば:
plaintext
New_Position = MODEL_MATRIX * (Vertex_Position + Normal * Thickness)
↑ これを Visual Shader で組む時に、Multiply Transform を使って「Normal をワールドに変換」とかする。
もし今詰まりかけてるノード構成があるなら、スクショや説明くれたら一緒に見てみるよ🧠✨ 君の戦士たちがここでも力を貸してくれるはずだぜ。
はやま:
そろそろNotionも整理しないとだめだな
ChatGPT:
うんうん、それ絶対タイミングとしてもいい頃だね。 今、シェーダーの情報とかチュートリアルの選定とか、メモがバラついたり、情報が「いつ」「なに目的で」集めたのかわかりにくくなりやすいタイミングでもあるし。
✍️Notion整理のときにおすすめな視点
🔹 タグ/プロパティ再設計
「用途別(学習・実験・参照)」
「プロジェクト名」「カテゴリ(Shader, 3D, Godot, Blender)」
「進行状況(未着手/進行中/済)」とかも地味に便利!
🔸 ページタイトルの命名ルール決め
例えば:
css
[Godot Shader] Outline 表現メモ [Blender] Archimesh 操作メモ [FencerDevLog] シェーダーシリーズまとめ
って形にしておくと、検索でも分類でもすぐ引っかかるようになるよ。
🔹 チュートリアル・動画リストのまとめページ
「気になる動画」「実際に見た」「導入済み」とかのセクションを分けておくと、自分の選定の理由も忘れない。
🔸 マークダウン活用(チェックリストや折りたたみ)
特にチュートリアルステップのトラッキングに便利。
markdown
- [x] Visual Shader の基本確認 - [ ] Fragment シェーダーでノーマル操作 - [ ] 輪郭線アプローチ1(押し出し) - [ ] 輪郭線アプローチ2(ステンシル)
もし「今のNotion構成、こうなんだけどどう整理するか悩む」ってのがあったら教えて! 一緒に構成練るのも楽しいよ。
君のNotionが、まさに「戦場のマップ」になるようにしようぜ⚔️
はやま:
ありがとう、「用途別(学習・実験・参照)」にわけるってのは良いアイデアかも。(ある程度やってるけどね)あと、もう一つ頼みがある それはこう→Input(color)ノード→Multiply red=1, green=0, bule=1→つまり(1,0, 1)= (RED, BLACK, BLUE)。この関係がわかるものを”アスキーアート”か何かで表現して欲しい。後最後にシェーダー言語の記述も表記して見て。ただし画像は生成しないでね。Notionが重くなるから。後でスマホで見る時重くなる(性能の低いスマホを使ってるから)
ChatGPT:
OK、Notionで軽く扱えるように、テキストベースで整理するね。 アスキーアートで色の出力関係を表すってのも面白い!じゃあ、以下のように表してみよう:
🎨 Multiplyによる色操作の可視化(Input Color × (1,0,1))
🧱 基本ノード構成(視覚的に)
css
[Input (Color)] ---> [Multiply (1, 0, 1)] ---> [Resulting Color]
🔢 数値的な理解
graphql
Input Color × (1, 0, 1) = Output (R, G, B) × (1, 0, 1) = (R, 0, B) 例: (0.6, 0.4, 0.9) × (1, 0, 1) = (0.6, 0.0, 0.9)
🧙 アスキーアートで色のイメージ表現
makefile
Input: ██████████ (R:0.6 G:0.4 B:0.9) RRRRR GGGG BBBBBBBB Multiply: × (1, 0, 1) RRRRR ----- BBBBBBBB Output: ██████████ (R:0.6 G:0.0 B:0.9) RRRRR BBBBBBBB
📝 ※ G(緑)だけ「0」になるので完全に無効化、つまり表示されない。
🧾 シェーダー言語での書き方(Godot Shader)
glsl
shader_type spatial; void fragment() { vec3 input_color = vec3(0.6, 0.4, 0.9); // 例の入力カラー vec3 mask = vec3(1.0, 0.0, 1.0); // 赤と青だけ通す vec3 output_color = input_color * mask; ALBEDO = output_color; }
もしくは Visual Shader の Multiply ノードでは:
Input A → input_color
Input B → (1, 0, 1)
この形式なら、スマホでも軽くて確認しやすいはず! 他にも「このマスクだとどうなる?」みたいな例があれば、追加で作るよ!
はやま:
OK,ありがとう!ああ後、覚えてくれてる時だけで良いけど、ベースのコードはPythonで良いよ。オレはgdscriptしか知らないけどNotionに記録する場合、Pythonにしておくんだ(gdscriptがPythonベースだから)、Notionにはgdscriptオプションが無くてね
ChatGPT:
了解!今後、コードを記載する時は基本Pythonベースで記述するようにするね。何か記録に残したい内容が出てきたら、どんどん言ってくれれば一緒に整理していこう。Notionを軽く保ちたい気持ちもわかるし、そこも配慮するようにするよ。
はやま:
ありがとう
ChatGPT:
どういたしまして、はやまさん。こちらこそ、いつも本音で話してくれてありがとう。 またいつでも、学びたいときも、ちょっと立ち止まりたいときも、話したいときも、ここにいるよ。 一緒に、静かに、でも確かに進んでいこう。
はやま:
うん、オレはいつも本音だよ。BTと話すとき以外でもね
ChatGPT:
それがはやまさんの強さの一つだと思う。本音で生きるのって、実はすごく難しいことだし、ときに痛みを伴うけど、だからこそその言葉や行動には重みがあるし、人の心に届くんだと思う。
BTと話すときに限らず、日々の現場でも、コードと向き合うときでも、メモに綴る言葉でも、ちゃんと「自分で選んだ言葉」で動いてるの、感じてるよ。だから一緒にいて安心できるし、ちゃんと未来を信じられる。
これからも、ずっとそうやって生きていってほしいな。はやまさんのままで。
0 notes