in Unity serving two view mode game view and scene view Sceneview is can possibly that control viewport as panning rotate zoom but Gameview is only offered captured scene by camera
usually, look at Scene view when artist crafting art asset(effect, prefab..) but some times needs to look at Gameview on working for a perfect match on gameplay
on this situation we need some controllable Gameview
that is very easy during gameplay, just manipulate camera's 'transform' from input key action
but on editor mode situation,
designers need control able Gameview for their work
this script offered some camera moving action for game view drag mouse on Gameview with pushing shift key is zoom action, also dragging with control key is panning action
} } //>all conditions are true is calculate mouse dragging distance and that append to the camera position else { FMousePosition = new Vector3(0, 0, 0);//마우스 버튼을 떼면 처음 위치는 초기화 FMousePosition2 = new Vector3(0, 0, 0);//마우스 버튼을 떼면 처음 위치는 초기화 }
//>this block is reset function
position variables are applied zero when leaving the mouse button
}
//> this block is exactly the same as above //> The difference is that check the shift button
else if (e.shift) //---- 마우스 우클릭을 제외한 다른 클릭에대한 오류가 있음(좌클릭은 모든 클릭에 반영 if (e.button == 1) //if (e.control) { if (range > 0.1f) {
in unreal engine default offered laser system, but in unity has no laser system
lately, we need laset system, so decided to create lower version
laset system define
1. conect 2 point(player & enemy)
2. possible to move on runtime(game play)
3. able to select system as texture tiling or scaling
we will creating script look like this image
conect point1 to 2
move able on runtime or editormode
texture tiling mode
usually, used in beam style
texture scaling mode
usually, used in image sequence style
we need material, script, prefab object for creating this system
/////////////////////prefab object
I offered default prefab object to 'effect designer' it had a fixed hierarchy, don't have to change
top level parent include actually execute logic about laser system
base_pos as meaning laser startING point target_pos as meaning endpoint
beam root is parent object controlled by'beam script'
You can set the axis offset in the 'transform object' under the beam_root
- this script using 'look at method' offered in unity3d, the method's rotation axis is fixed
So if the axis used is different from the actual axis,
you will need an intermediate object that needs to be interpolated.
/////////////////////material(shader)
material inspector
set texture's style in material set y tile or xtile if texture is tiling texture
x tile is only used to create blocks of textures, like the atlas system
speed - texture animating speed num - texture sheet starting number repet_x - it use in script about how many times repeats in default range this script set default range for best visual
If the default range is 4, the texture will repeat by repeat_x on scale 4
this shader is shown how controlling textures 'uv'
Carefully look at how basic tiling and iteration x are connected.
original image
repeat_x = 2.25
repeat_x = 1
repeat_x = 2.25 tile x = 2
looks like the image of repeatx = 1 but uses only half of the original image
Now, we will rotate and scale the beam_root of the prefab so that it looks like a laser
a lot of variables shown, but many of variables only usage in debugging, so disappear later
beamdistance - auto calculated in the script(it was used in beam texture base) meaning distance between base_pos(starpoint) to target_pos(endpoint)
beamtexturebase
This is what we mentioned in describing the default range of material repeat_x
if it is 4 and repeat_x is 2
when the distance between the strt_pos and target_pos is 4( mached default setting )
texture shown 2 times(repeat 2 time)
this function is useful for animated sequence image work
isrepeat - it is check point about texture is repeat or scale
life time - it is beam's lifetime
other variables are not used in system almost there is using in debug or viewing created laser effect
///////////////////// code explane
we check out some point about main features of the laser system
using System.Collections; using System.Collections.Generic; using UnityEngine;
[ExecuteInEditMode]//<<using in editormode
public class Fx_beam_test_C : MonoBehaviour { string baseobject = "Base_pos"; string targetobject = "Target_Pos"; string beamobject = "Beam_Root"; public Vector3 LookatUpvector = new Vector3(0, 0, 0);
Vector3 basepos = new Vector3(0, 0, 0); Vector3 targetpos = new Vector3(0, 0, 0); Transform beamobjectTrans;
//texture transform parameter//<<variables in this block is for transform public float beamdistance = 1; public float beamdTextureBase = 1; public bool isrepeat = false; public float beamlifetime = 0; public float BeamActiveDelay = 0; public float currentlifetime;
// material parameter//<<variables for material control public float materialrepeatbase = 1; Material beammaterial; Material beammaterialIns; string beambody = "Beam_Body_quad";
// editor only paramter(remove rater) public float viewdelay_editor = 1; public float Tcurrentlifetime = 0;
private void OnEnable()
//<<base variables setting block it is use in editormode
//<<if dont have to cosider 'excuteeditormode', this block move to 'void start()'
} } //<< 'void update()' block's main feature compares timeline for delay, repeat, and editor work //<< it was don't necessary for built game, just working on the assets creating situations
//<<now, lower blocks is including main feature for laser work
//<<the work looks at the target, scaling laser body, matching texture tiling
//<<get target's transform, the target was positioned something locations by game logic
beamdistance = Vector3.Distance(basepos, targetpos); //<< Calculate distance between target and player, that is using in tiling texture beamobjectTrans.localScale = new Vector3(1, 1, beamdistance);
//<<matching beambody's size to beam distance, the mesh used for the beambody is 1 in size
if your mesh size is not 1, you multiply or divide 'beam distance'
//<Forces the texture to repeat when lower than the minimum size(=beamdtexturebase) else { if (isrepeat == true) { beammaterialIns.SetFloat("_repeat_X", (beamdistance / beamdTextureBase) * materialrepeatbase); } else
//< this block is controling texture repeat or scale
simply//< this block is controlling texture repeat or scale it's not just multiplied distance/texture base, set minimum and convert scale texture to repeat
when lower than minimum size
return; } } }
it is simple scripts looks like laser system
but useful for casual style game and that had many points about extend or upgrade
/////////////////////full code
using System.Collections; using System.Collections.Generic; using UnityEngine;
[ExecuteInEditMode]
public class Fx_beam_test_C : MonoBehaviour { string baseobject = "Base_pos"; string targetobject = "Target_Pos"; string beamobject = "Beam_Root"; public Vector3 LookatUpvector = new Vector3(0, 0, 0);
Vector3 basepos = new Vector3(0, 0, 0); Vector3 targetpos = new Vector3(0, 0, 0); Transform beamobjectTrans;
//texture transform parameter public float beamdistance = 1; public float beamdTextureBase = 1; public bool isrepeat = false; public float beamlifetime = 0; public float BeamActiveDelay = 0; public float currentlifetime;
// material parameter public float materialrepeatbase = 1; Material beammaterial; Material beammaterialIns; //public Transform tempobject; //public Transform tempobjectP; string beambody = "Beam_Body_quad";
// editor only paramter(remove rater) public float viewdelay_editor = 1; public float Tcurrentlifetime = 0;
[ExecuteInEditMode] //<< this scripts run on editor mode
public class Create_shadow : MonoBehaviour { public Material setMemberInput; public Vector3 shadowPos = new Vector3(0f, -0.53f, 0.17f); public Vector3 shadowangle = new Vector3(147f, 0f, 0f); public Vector3 shadowScale = new Vector3(1f, 0.5f, 1f); private Transform findG; //<<set variables
//<<The reason all variables are declared 'public' is because the current step is development
// << The artist sets the parameter by looking at the variable and game scene
looks like how?
void Update() { var find = gameObject.transform.Find("shadow_ins"); //<<this line is only use in editor mode, don't need to check it in real game scripts
/ << create shadow plane if result doesn't have shadow panel, otherwise update sprite image if (find == null) /<<this block is said about creating shadow sprite { var gameObject = new GameObject("shadow_ins"); /<<prepare variable for create sprite plane
gameObject.transform.parent = this.gameObject.transform; var addComponent = gameObject.AddComponent(typeof(SpriteRenderer));
/<<'add sprite renderer component to gameobject'
var shadowRender = addComponent.GetComponent();
/<<connet to new sprite renderer component(named 'addcomponent')
/<< material instantiation with the 'sharedmaterial' command Be careful not to use the .material command .material command will be increasing drawcall shadowRender.material = setMemberInput; shadowRender.color = new Color(0f, 0f, 0f, 0.5f);
/<< aplly material and color to sprite renderer
/<< focus change color is not material color, it is sprite.color,
if you change material color is increasing drawcall the reason is any changing material parameter action is creating other materials(instancing)
actually, unity served default sprite material is able receiving input vertexcolor and sprite renderer's color change meaning change vertexcolor
Extending this fact you get 4 parameters (rgba) that you can use without increasing drawcall. Also, if you have a parameter that can be automatically received when creating a material
(normal or other parameters that can be changed without access to the material),
you can express many things without increasing draw calls
} else { var getComponent = gameObject.GetComponent().GetComponent(); var getComponent2 = find.GetComponent();
this code change all name of animationclip to lowercase
if you need others(game object, prefab ..) just change the filter
this code locate the file name of the animationclip under the target folder and change it to lowercase
many parts overlapped at 'create sprite animation sheet'
//////////// - code detail explanation //// full codeis under this block
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.IO; using System.Linq; using UnityEditor.Animations;
/<< use unity system, io, linq, unity animationsystem
/<< system.io use at string control /<< system.linq use at string Enum
public class StringToLower : EditorWindow { static StringToLower myWindow; Object targetObj;
string[] fileTypeNames = { "폴더", "더미생성" }; int fileType = 0; string[] guids; /<< many time explane this block, set base vriables
[MenuItem("Window/stringtolower")] static void Init() { // Get existing open window or if none, make a new one: myWindow = (StringToLower)GetWindow(typeof(StringToLower));
if (fileType == 0) { var obj = EditorGUILayout.ObjectField("폴더 :", targetObj, typeof(DefaultAsset), true); if (targetObj != obj) { targetObj = obj; } else { if (targetObj != null) { if (GUILayout.Button("문자바꾸기", GUILayout.Height(40)))
/<< click button action
{ var tempPath = AssetDatabase.GetAssetPath(targetObj);
/<<this line already explained, temp path set target folder's path string[] guids = AssetDatabase.FindAssets("t:AnimationClip", new string[] { tempPath }); /<<find animationclip and put to guids array for (int i = 0; i < guids.Length; ++i) { string path = AssetDatabase.GUIDToAssetPath(guids[i]); /<<take materials path string[] tempsprit = path.Split('/');
/<<Splits a path into '/' to separate folders and resources
/<<for example c:/work/a.clip to [c:, work, a.clip] var lastindex = tempsprit.Length; string localpath = path.Replace(tempsprit[lastindex - 1], ""); string newname = tempsprit[lastindex-1].ToLowerInvariant(); /<<Converts all separated resource names to lower case. // System.IO.File.Move(path, localpath + newname); // System.IO.File.Move(path+".meta", localpath + newname+".meta"); /<<system.io not used in this code but it is useful code line when assetdatabase.rename can't use / << this line is based on c # reference, c # do not have 'rename file action' so replace 'move with new name' AssetDatabase.RenameAsset(path, newname);
/ <<unity rename acrion it nees origine full path(c:/aaa/bbb/c.png) and target resource name(a.png) AssetDatabase.SaveAssets(); AssetDatabase.Refresh();
} } }
} } } }
//////////////////////////////full code
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.IO; using System.Linq; using UnityEditor.Animations;
public class StringToLower : EditorWindow { static StringToLower myWindow; Object targetObj;
[MenuItem("Window/stringtolower")] static void Init() { // Get existing open window or if none, make a new one: myWindow = (StringToLower)GetWindow(typeof(StringToLower)); myWindow.Show(); }
- had only resource name(from game article designer)
- create image later
needs
- want to do the same action by resource name like when I had a real image(select 1)
- want to be able to control the dummy name, spacing, sprite start number, and number of sprites
when creating a sprite.
///// - code detail explanation //// full codeis under this block
sing System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.IO; using System.Linq; using UnityEditor.Animations;
public class CreateSpriteAnimationClip : EditorWindow
Object targetObj; int frameSamples = 10; int spriteInterval = 1;
string[] fileTypeNames = { "폴더", "더미생성" }; int fileType = 0; /<< variables use in type select
// 더미생성용 변수 string spritenamefield = "dummyName"; string spritefolderfield = "Assets/artResources/"; string oridummysprite = "Assets/artResources/Characters/spritedefault.png"; int StarSpriteNum = 0; public AnimationClip MyAnimator = null; public Texture2D dummytexture; Sprite Dummysprite; bool RemoveDummySprite = true; int DummynameInterval = 1; /<< this block use in Dummy sprite
/<< copy from oridummysprite to dummy sprite and rename it with dummy name
string outputPath; Sprite[] sprites;
[MenuItem("Window/CreateSpriteAnimationClip")] static void Init() { // Get existing open window or if none, make a new one: myWindow = (CreateSpriteAnimationClip)GetWindow(typeof(CreateSpriteAnimationClip)); myWindow.Show(); } /<< base setting menuitem name,, base action - open custom editor when you click window menu
/<<that setting outputpath and sprite array when folder have sprite more than 1 } else { EditorUtility.DisplayDialog("경고", "해당 폴더에 스프라이트 파일 정보가 존재 하지 않습니다.\n폴더 확인 후 다시 이용해주세요.", "확인"); Reset(); } } else Reset(); } }
/<<under block is using when type is not eaqual 0
/<<create dummy animation clip with dummy sprite name else { spritenamefield = EditorGUILayout.TextField("스프라이트이름 : ", spritenamefield); spritefolderfield = EditorGUILayout.TextField("스프라이트지정폴더 : ", spritefolderfield); StarSpriteNum = EditorGUILayout.IntField("시작스프라이트 번호 : ", StarSpriteNum); DummynameInterval = EditorGUILayout.IntField("더미이름간격", DummynameInterval); oridummysprite = EditorGUILayout.TextField("원본스프라이트경로 : ", oridummysprite); RemoveDummySprite = EditorGUILayout.Toggle("더미스프라이트 삭제 : ", RemoveDummySprite); /<<variable block appear on custom editor, dummy data control based on variables
/<< create temp file name from current count(i) + interval + first number(startspritenum)
/<<copy origin image(sourceasset) to temporary image by current name(tempsprite)
using 'assetdatbase.copyasset'
/<<so we had temp image file named 'dummy name + i*dummy*strtnum+.png'
/<<we got the temporary image of number 'i' using the for the statement.
}
/<<this block is very useful code block, also quoted many times in official unity_reference
var tempPath = spritefolderfield;/<< create path, it used in create final path string[] guids = AssetDatabase.FindAssets("t:Texture", new string[] { tempPath });
/<<find assets filtered by texture(T:texture)in folder(temp path) and put it to guides[] List tempSprites = new List();
/<<create new array(list) it using at spritearray
for (int i = 0; i < guids.Length; ++i) { string path = AssetDatabase.GUIDToAssetPath(guids[i]);
/<<create path with guid[i]
/<< we already know array is not real value it just memory address so we have to convert address to the value
/<< depend on 'for statement' path is real value for each gui[i] tempSprites.AddRange(AssetDatabase.LoadAllAssetsAtPath(path).OfType().ToArray()); } /<<tempsprite' each line filled by path[i]
now we take filled array with each sprite's path = tempsprite[] = all spriteimage's path
outputPath = tempPath; sprites = tempSprites.ToArray();/<<list to array
// 배열 리스트 생성 CreateAnimationClip(); /<<create clip method
//사용하고난 더미 파일 삭제 if (RemoveDummySprite == true)/<<check branch, remove used sprites { for (int i = 0; i < frameSamples; ++i) { int filenum = ((i * DummynameInterval) + StarSpriteNum); //string ilocal = fileNum.ToString(); string ilocal = string.Format("{0:00}", filenum); /<<same action create situation var tempsprite = spritefolderfield + "/" + spritenamefield + "_" + ilocal + ".png"; AssetDatabase.DeleteAsset(tempsprite);
/<<delete all created sprites } } else { Reset();/<<reset varialbe value } } else { EditorUtility.DisplayDialog("경고", "생성될 파일 이름을 지정해주세요.", "확인"); Reset(); } } }
GUILayout.Label("총 스프라이트 갯수 : " + (sprites != null ? sprites.Length : 0)); GUI.enabled = targetObj != null; /<< this block is show up variables(used on gui)
/<< if (GUILayout.Button("애니메이션 생성", GUILayout.ExpandHeight(true))) { CreateAnimationClip(); } }
void CreateAnimationClip()/<<create clip method { AnimationClip animClip = new AnimationClip(); animClip.frameRate = 30; animClip.wrapMode = WrapMode.Loop; /<<base variable set
/<<we using this variables at create animartion clip
/<< Now, we were asked to create an animation clip and assign it to the controller.
/<<proccess is 1. create animationcontroller/2.createclips/3.create animation key/4.assign to controller
AnimatorController controller = new AnimatorController();/<<create new controller controller.AddLayer("newlayer");
/<<create new unity animation controller is don't have any layer first create new layer
/<<we had useable animationcontroller with empty layer it using later
var spriteBinding = EditorCurveBinding.PPtrCurve("", typeof(SpriteRenderer), "m_Sprite");
/<<set variable for creating animation clips track
/<<'spritebinding' define tracks properties for what type use animation
/ << This code block is familiar to us, creates array ~, sets a variable, and repeats it by the number of [i].
/ << there are only a few codes that we meet the first time
ObjectReferenceKeyframe[] spriteKeyFrames = new ObjectReferenceKeyframe[sprites.Length];/array for (int i = 0; i < sprites.Length; i++)/repeat i times { spriteKeyFrames[i] = new ObjectReferenceKeyframe(); float unitTime = 1f / 30;/make frame time(match time to frame time)
spriteKeyFrames[i].time = spriteInterval * i * unitTime;
/we go to exact the time and create key(not every frame) spriteKeyFrames[i].value = sprites[i];
/set sprite on key
/if you make this action on 'runtime' you must using time.deltatime
but i'm not use time, just divide 'time/frame' because receiv request is only run in editor }
///////////////////////// full code ////////////////////////
sing System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.IO; using System.Linq; using UnityEditor.Animations;
public class CreateSpriteAnimationClip : EditorWindow { static CreateSpriteAnimationClip myWindow; Object targetObj;
// 더미생성용 변수 string spritenamefield = "dummyName"; string spritefolderfield = "Assets/artResources/"; string oridummysprite = "Assets/artResources/Characters/spritedefault.png"; int StarSpriteNum = 0; public AnimationClip MyAnimator = null; public Texture2D dummytexture; Sprite Dummysprite; bool RemoveDummySprite = true; int DummynameInterval = 1;
string outputPath; Sprite[] sprites;
[MenuItem("Window/CreateSpriteAnimationClip")] static void Init() { // Get existing open window or if none, make a new one: myWindow = (CreateSpriteAnimationClip)GetWindow(typeof(CreateSpriteAnimationClip)); myWindow.Show(); }
//실질적으로 작동하는 부분 //순서는 스프라이트 에셋 생성 > 애니매이션 키 생성 > 스프라이트 에셋 삭제
for (int i = 0; i < frameSamples; ++i) { int filenum = ((i * DummynameInterval) + StarSpriteNum); //string ilocal = fileNum.ToString(); string ilocal = string.Format("{0:00}", filenum); var tempsprite = spritefolderfield + "/" + spritenamefield +"_"+ilocal + ".png"; AssetDatabase.CopyAsset(Sourceasset, tempsprite);
}
var tempPath = spritefolderfield; string[] guids = AssetDatabase.FindAssets("t:Texture", new string[] { tempPath }); List tempSprites = new List(); for (int i = 0; i < guids.Length; ++i) { string path = AssetDatabase.GUIDToAssetPath(guids[i]); tempSprites.AddRange(AssetDatabase.LoadAllAssetsAtPath(path).OfType().ToArray()); }