I copied the whole switch/case part to the Update to be able to change the modes also at runtime.
but I want also to be able to change the morphTime at runtime without the need to switch a mode first. for example if the enum mode is now MultiColorMorph and then if i'm changing only the morphTime then affect the change on the current mode.
I'm not sure about the other modes but the two modes that use the morphTime are :
RandomSingleColorMorphing and RandomMultiColorMorphing
IEnumerator RandomSingleColorMorphing(LineRenderer lineRendererToChange, float timeToMorph)
{
float time = 0;
Color initialColor = lineRendererToChange.colorGradient.colorKeys[0].color;
//this reduces colorkey amount to 2 just in case.
SetSingleColor2(lineRendererToChange, initialColor);
while (true)
{
initialColor = lineRendererToChange.colorGradient.colorKeys[0].color;
Color targetColor = RandomColor();
time = 0;
while (time < timeToMorph)
{
time += Time.deltaTime;
float progress = time / timeToMorph;
Color currentColor = Color.Lerp(initialColor, targetColor, progress);
SetSingleColor(lineRendererToChange, currentColor);
yield return null;
}
yield return null;
}
}
And
IEnumerator RandomMultiColorMorphing(LineRenderer lineRendererToChange, float timeToMorph)
{
float time = 0;
while (true)
{
GradientColorKey[] initialColorKeys = lineRendererToChange.colorGradient.colorKeys;
GradientColorKey[] newColorKeys = GenerateRandomColorKeys(initialColorKeys);
time = 0;
while (time < timeToMorph)
{
time += Time.deltaTime;
float progress = time / timeToMorph;
GradientColorKey[] currentColorKeys = GradientColorKeyLerp(initialColorKeys, newColorKeys, progress);
Gradient tempGradient = lineRendererToChange.colorGradient;
tempGradient.colorKeys = currentColorKeys;
lineRendererToChange.colorGradient = tempGradient;
yield return null;
}
yield return null;
}
}
The full code :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(LineRenderer))]
public class LineRendererColors : MonoBehaviour
{
public enum AnimationType { None, SingleColorMorph, MultiColorMorph, Shuffle, Shift };
public AnimationType myAnimationType;
LineRenderer myLineRenderer;
public float morphTime;
void Start()
{
myLineRenderer = this.GetComponent<LineRenderer>();
switch (myAnimationType)
{
case AnimationType.SingleColorMorph:
StartCoroutine(RandomSingleColorMorphing(myLineRenderer, morphTime));
break;
case AnimationType.MultiColorMorph:
StartCoroutine(RandomMultiColorMorphing(myLineRenderer, morphTime));
break;
case AnimationType.Shuffle:
StartCoroutine(ShuffleGradient(myLineRenderer, .5f));
break;
case AnimationType.Shift:
StartCoroutine(AnimateLoop(myLineRenderer));
break;
}
}
private void Update()
{
switch (myAnimationType)
{
case AnimationType.SingleColorMorph:
StartCoroutine(RandomSingleColorMorphing(myLineRenderer, morphTime));
break;
case AnimationType.MultiColorMorph:
StartCoroutine(RandomMultiColorMorphing(myLineRenderer, morphTime));
break;
case AnimationType.Shuffle:
StartCoroutine(ShuffleGradient(myLineRenderer, .5f));
break;
case AnimationType.Shift:
StartCoroutine(AnimateLoop(myLineRenderer));
break;
}
}
void SetSingleColor(LineRenderer lineRendererToChange, Color newColor)
{
lineRendererToChange.startColor = newColor;
lineRendererToChange.endColor = newColor;
}
void SetSingleColor2(LineRenderer lineRendererToChange, Color newColor)
{
Gradient tempGradient = new Gradient();
GradientColorKey[] tempColorKeys = new GradientColorKey[2];
tempColorKeys[0] = new GradientColorKey(newColor, 0);
tempColorKeys[1] = new GradientColorKey(newColor, 1);
tempGradient.colorKeys = tempColorKeys;
lineRendererToChange.colorGradient = tempGradient;
}
void SetSingleColor3(LineRenderer lineRendererToChange, Color newColor)
{
Gradient tempGradient = lineRendererToChange.colorGradient;
GradientColorKey[] tempColorKeys = tempGradient.colorKeys;
for (int i = 0; i < tempColorKeys.Length; i++)
{
tempColorKeys[i].color = newColor;
}
tempGradient.colorKeys = tempColorKeys;
lineRendererToChange.colorGradient = tempGradient;
}
IEnumerator ShuffleGradient(LineRenderer targetLineRenderer, float waitTime)
{
while (true)
{
ShuffleGradient(targetLineRenderer);
yield return new WaitForSeconds(waitTime);
}
}
void ShuffleGradient(LineRenderer targetLineRenderer)
{
GradientColorKey[] newColorKeys = targetLineRenderer.colorGradient.colorKeys;
for (int i = 0; i < newColorKeys.Length; i++)
{
Color tempColor = newColorKeys[i].color;
int randomIndex = Random.Range(0, newColorKeys.Length - 1);
newColorKeys[i].color = newColorKeys[randomIndex].color;
newColorKeys[randomIndex].color = tempColor;
}
Gradient tempGradient = targetLineRenderer.colorGradient;
tempGradient.colorKeys = newColorKeys;
targetLineRenderer.colorGradient = tempGradient;
}
IEnumerator RandomMultiColorMorphing(LineRenderer lineRendererToChange, float timeToMorph)
{
float time = 0;
while (true)
{
GradientColorKey[] initialColorKeys = lineRendererToChange.colorGradient.colorKeys;
GradientColorKey[] newColorKeys = GenerateRandomColorKeys(initialColorKeys);
time = 0;
while (time < timeToMorph)
{
time += Time.deltaTime;
float progress = time / timeToMorph;
GradientColorKey[] currentColorKeys = GradientColorKeyLerp(initialColorKeys, newColorKeys, progress);
Gradient tempGradient = lineRendererToChange.colorGradient;
tempGradient.colorKeys = currentColorKeys;
lineRendererToChange.colorGradient = tempGradient;
yield return null;
}
yield return null;
}
}
GradientColorKey[] GradientColorKeyLerp(GradientColorKey[] initialColorKeys, GradientColorKey[] endColorKeys, float progress)
{
GradientColorKey[] newColorKeys = new GradientColorKey[initialColorKeys.Length];
for (int i = 0; i < newColorKeys.Length; i++)
{
newColorKeys[i].color = Color.Lerp(initialColorKeys[i].color, endColorKeys[i].color, progress);
newColorKeys[i].time = initialColorKeys[i].time;
}
return newColorKeys;
}
//assigns new color to each colorkey and uses Time from incomingColorKeys
GradientColorKey[] GenerateRandomColorKeys(GradientColorKey[] incomingColorKeys)
{
GradientColorKey[] newColorKeys = new GradientColorKey[incomingColorKeys.Length];
for (int i = 0; i < newColorKeys.Length; i++)
{
newColorKeys[i].color = RandomColor();
newColorKeys[i].time = incomingColorKeys[i].time;
}
return newColorKeys;
}
//asumes Single color, 2 colorkeys
IEnumerator RandomSingleColorMorphing(LineRenderer lineRendererToChange, float timeToMorph)
{
float time = 0;
Color initialColor = lineRendererToChange.colorGradient.colorKeys[0].color;
//this reduces colorkey amount to 2 just in case.
SetSingleColor2(lineRendererToChange, initialColor);
while (true)
{
initialColor = lineRendererToChange.colorGradient.colorKeys[0].color;
Color targetColor = RandomColor();
time = 0;
while (time < timeToMorph)
{
time += Time.deltaTime;
float progress = time / timeToMorph;
Color currentColor = Color.Lerp(initialColor, targetColor, progress);
SetSingleColor(lineRendererToChange, currentColor);
yield return null;
}
yield return null;
}
}
//Basically Color.Lerp?
Color ColorLerpMath(Color firstColor, Color secondColor, float progress)
{
Vector3 firstRGB = new Vector3(firstColor.r, firstColor.g, firstColor.b);
Vector3 secondRGB = new Vector3(secondColor.r, secondColor.g, secondColor.b);
Vector3 difference = secondRGB - firstRGB;
Vector3 lerpedRGB = firstRGB + (progress * difference);
return new Color(lerpedRGB.x, lerpedRGB.y, lerpedRGB.z);
}
Color RandomColor()
{
return new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f));
}
//returns the gradient with a copy of the first key for intersection purposes.
Gradient AddInitialCopy(Gradient incomingGradient)
{
List<GradientColorKey> newColorKeys = new List<GradientColorKey>(incomingGradient.colorKeys);
Color interSectionColor = newColorKeys[0].color;
newColorKeys.Insert(0, new GradientColorKey(interSectionColor, 0));
Gradient newInitGradient = new Gradient();
newInitGradient.colorKeys = newColorKeys.ToArray();
return newInitGradient;
}
//remove first and last keys since they dont shift.
List<GradientColorKey> RemoveFirstAndLast(Gradient incomingGradient)
{
List<GradientColorKey> currentColorKeys = new List<GradientColorKey>(incomingGradient.colorKeys);
currentColorKeys.RemoveAt(currentColorKeys.Count - 1);
currentColorKeys.RemoveAt(0);
return currentColorKeys;
}
Color GetIntersectionColor(List<GradientColorKey> incomingKeys, int lowestIndex, int highestIndex)
{
Color firstColor = incomingKeys[lowestIndex].color;
Color lastColor = incomingKeys[highestIndex].color;
float distance = 1 - (incomingKeys[highestIndex].time - incomingKeys[lowestIndex].time);
float colorLerpAmount = (1f - incomingKeys[highestIndex].time) / distance; ;
Color newIntersectionColor = Color.Lerp(lastColor, firstColor, colorLerpAmount);
return newIntersectionColor;
}
//accepts max 7 colors, 1st and last should be at 0 and 1
IEnumerator AnimateLoop(LineRenderer lineRendererToChange, float movementPerTick = .001f)
{
lineRendererToChange.colorGradient = AddInitialCopy(lineRendererToChange.colorGradient);
while (true)
{
List<GradientColorKey> currentColorKeys = RemoveFirstAndLast(lineRendererToChange.colorGradient);
float highestTime = 0;
float lowestTime = 1;
int highestIndex = currentColorKeys.Count - 1;
int lowestIndex = 0;
//Move all inner ones.
for (int i = 0; i < currentColorKeys.Count; i++)
{
GradientColorKey tempColorKey = currentColorKeys[i];
float newTime = tempColorKey.time + movementPerTick;
if (newTime > 1)
{
newTime = newTime - 1;
}
tempColorKey.time = newTime;
currentColorKeys[i] = tempColorKey;
if (newTime < lowestTime)
{
lowestTime = newTime;
lowestIndex = i;
}
if (newTime > highestTime)
{
highestTime = newTime;
highestIndex = i;
}
}
Color newIntersectionColor = GetIntersectionColor(currentColorKeys, lowestIndex, highestIndex);
currentColorKeys.Insert(0, new GradientColorKey(newIntersectionColor, 0));
currentColorKeys.Add(new GradientColorKey(newIntersectionColor, 1));
Gradient tempGradient = lineRendererToChange.colorGradient;
tempGradient.colorKeys = currentColorKeys.ToArray();
lineRendererToChange.colorGradient = tempGradient;
yield return null;
}
}
void AssignGradient(LineRenderer targetLineRenderer, Gradient newGradient)
{
targetLineRenderer.colorGradient = newGradient;
}
void DrawTestLine()
{
Vector3 firstPos = new Vector3(-5, 0, 0);
Vector3 secondPos = new Vector3(5, 0, 0);
int resolution = 100;
myLineRenderer.positionCount = resolution;
myLineRenderer.SetPositions(MakeLine(firstPos, secondPos, 100));
}
//makes a line from point A to point B with resolution of size points
Vector3[] MakeLine(Vector3 initPos, Vector3 endPos, int points)
{
Vector3 difference = endPos - initPos;
Vector3[] newLine = new Vector3[points];
Vector3 differencePerPoint = difference / (float)(points - 1);
for (int i = 0; i < points; i++)
{
newLine[i] = initPos + (differencePerPoint * i);
}
return newLine;
}
}
Related
I am working on custom enum popup with search and facing next problem. When clicking button to show popup list of enums I can hover over that list and select items inside, but also I can as always move mouse outside popup rect and move around. And when I hover over other GUI element it reacts to that movement (hover highlight or so happens). I remembered that default Unity's enum don't have this feature and it blocks all events outside popup's rect exclude outside mouse click to close this popup.
So... My question is: How can I implement this feature in my popup window? I look into Unity's source code and don't find anything related to this. Except one moment when they are using internal function "GUI.GrabMouseControl(id);"
There are this internal function for enum button where they block mouse control somehow:
// A button that returns true on mouse down - like a popup button
internal static bool DropdownButton(int id, Rect position, GUIContent content, GUIStyle style)
{
Event evt = Event.current;
switch (evt.type)
{
case EventType.Repaint:
var hovered = position.Contains(Event.current.mousePosition);
if (showMixedValue)
{
BeginHandleMixedValueContentColor();
style.Draw(position, s_MixedValueContent, id, false, hovered);
EndHandleMixedValueContentColor();
}
else
style.Draw(position, content, id, false, hovered);
break;
case EventType.MouseDown:
if (GUIUtility.HitTest(position, evt) && evt.button == 0)
{
GUI.GrabMouseControl(id);
Event.current.Use();
return true;
}
break;
case EventType.MouseUp:
if (GUI.HasMouseControl(id))
{
GUI.ReleaseMouseControl();
Event.current.Use();
}
break;
case EventType.KeyDown:
if (GUIUtility.keyboardControl == id && evt.character == ' ')
{
Event.current.Use();
return true;
}
break;
}
return false;
}
I think that may be that magic thing to block mouse hovering. Also I think that GUIUtility.hotControll is second canditate to solve my issue. But I dont know how properly use it in my OnGUI() method. I am trying to it and get not correct result,
but I blocked hovering outside popup's rect. But it always spam console with these logs:
Should not grab hot control with an active capture. So I dropped this idea with my implementation, cause of these logs...
There are my code of popup window content:
using System;
using UnityEditor;
using UnityEngine;
public class SearchablePopup : PopupWindowContent
{
#region Popup Properties
private const float SymbolVerticalOffset = 0.75f;
private const int ClearButtonSize = 12;
private const string SearchControl = "searchablePopup_ctrl";
#endregion
public static void Show(Rect from, Type type, int current,
Action<int> onSelectionMade, int elementsToShow, int elementHeight,
int searchHeight, Texture backgroundTexture,
GUIStyle searchStyle, GUIStyle clearButtonStyle, GUIStyle elementStyle,
Color hover, Color selected, Color marker)
{
if (type.IsEnum is false) return;
var window = new SearchablePopup(type, current, onSelectionMade,
(int)from.width, elementsToShow, elementHeight, searchHeight,
backgroundTexture, searchStyle, clearButtonStyle, elementStyle,
hover, selected, marker);
PopupWindow.Show(from, window);
}
private readonly FilteredList _filteredList;
private readonly Action<int> _onSelectionMade;
private readonly int _width;
private readonly int _elementsToShow;
private readonly int _rowHeight;
private readonly int _searchHeight;
private readonly float _clearButtonPadding;
private readonly bool _clearButtonValid;
private readonly GUIStyle _searchStyle;
private readonly GUIStyle _searchTooltipStyle;
private readonly GUIStyle _clearButtonStyle;
private readonly GUIStyle _elementStyle;
private readonly Texture _backgroundTexture;
private readonly Texture _hoverTexture;
private readonly Texture _selectedTexture;
private readonly Texture _selectedCircleTexture;
private int _current;
private int _hover;
private int _keyboardIndex;
private int _scroll;
private int _controlHash = "SearchablePopup".GetHashCode();
private Vector2 _scrollPosition;
private Vector2 _clickPosition;
private bool _clickedThisFrame;
public SearchablePopup(Type enumType, int current, Action<int> onSelectionMade,
int width, int elementsToShow, int rowHeight, int searchHeight, Texture backgroundTexture,
GUIStyle searchStyle, GUIStyle clearButtonStyle, GUIStyle elementStyle,
Color hover, Color selected, Color marker)
{
_filteredList = new FilteredList(enumType, current);
_hoverTexture = SmallTexture(hover);
_selectedTexture = SmallTexture(selected);
_selectedCircleTexture = DrawCircle(4, marker);
_current = current;
_hover = _current;
_scroll = _current;
_keyboardIndex = _filteredList.CurrentIndex;
_onSelectionMade = onSelectionMade;
_elementsToShow = elementsToShow;
_width = width;
_rowHeight = rowHeight;
_searchHeight = searchHeight;
_backgroundTexture = backgroundTexture;
_searchStyle = searchStyle;
_clearButtonValid = clearButtonStyle != null;
_clearButtonStyle = clearButtonStyle;
_clearButtonPadding = _clearButtonValid ? clearButtonStyle.padding.left : 4;
_elementStyle = elementStyle;
if (_clearButtonValid is false)
{
_elementStyle = new GUIStyle(_elementStyle);
_elementStyle.alignment = TextAnchor.MiddleLeft;
}
_searchTooltipStyle = new GUIStyle(_searchStyle);
_searchTooltipStyle.normal.textColor *= 0.75f;
_searchTooltipStyle.hover.textColor = _searchTooltipStyle.normal.textColor;
_searchTooltipStyle.fontSize = (int)(_searchTooltipStyle.fontSize * 0.75f);
}
public override Vector2 GetWindowSize()
{
float height = Mathf.Min(
_filteredList.Entries.Count, _elementsToShow) * _rowHeight
+ _searchHeight;
//Strange hot-fix for Unity's Scrollview:
//We are increasing total height of our window's rect
//to be a litte bigger than actual content because
//if Scrollview's height >= Window's height than scrollbar is displayed
//what we don't want to see if our current count of entires is less than show amount
if (_filteredList.Entries.Count < _elementsToShow)
height += 0.25f;
return new Vector2(_width, height);
}
public override void OnOpen()
{
base.OnOpen();
EditorApplication.update += Repaint;
}
public override void OnClose()
{
base.OnClose();
EditorApplication.update -= Repaint;
}
private void Repaint()
{
EditorWindow.focusedWindow.Repaint();
}
public override void OnGUI(Rect rect)
{
GUI.DrawTexture(rect, _backgroundTexture);
if (Event.current.type == EventType.MouseDown)
{
_clickedThisFrame = true;
_clickPosition = Event.current.mousePosition;
}
Rect search = new Rect(0, 0, rect.width, _searchHeight);
Rect clear = Rect.MinMaxRect(search.xMax - ClearButtonSize - _clearButtonPadding,
search.center.y - ClearButtonSize * 0.5f, rect.xMax - _clearButtonPadding,
search.center.y + ClearButtonSize * 0.5f);
Rect scroll = Rect.MinMaxRect(0, search.yMax, rect.xMax, rect.yMax);
HandleKeyboardInput();
DrawSearch(search, clear);
DrawScroll(scroll);
_clickedThisFrame = false;
}
private void DrawSearch(Rect search, Rect clear)
{
GUI.FocusControl(SearchControl);
GUI.SetNextControlName(SearchControl);
var filter = TextfieldWithTooltip(search, _filteredList.Filter,
"Type to search...", _searchStyle, _searchTooltipStyle);
if (_filteredList.Refresh(filter))
{
_scrollPosition = Vector2.zero;
}
if (string.IsNullOrEmpty(_filteredList.Filter) is false)
{
if (_clearButtonValid)
{
GUI.Box(clear, GUIContent.none, _clearButtonStyle);
}
else
{
GUI.Box(clear, "x", GUI.skin.label);
}
if (_clickedThisFrame && clear.Contains(_clickPosition))
{
_filteredList.Refresh("");
_scrollPosition = Vector2.zero;
}
}
}
private void DrawScroll(Rect scroll)
{
Rect contentRect = new Rect(0, 0,
scroll.width - GUI.skin.verticalScrollbar.fixedWidth,
_filteredList.Entries.Count * _rowHeight);
_scrollPosition = GUI.BeginScrollView(scroll, _scrollPosition, contentRect);
Rect element = new Rect(0, 0, scroll.width, _rowHeight);
var eventType = Event.current.type;
for (int i = 0; i < _filteredList.Entries.Count; i++)
{
if (_scroll == _filteredList.Entries[i].Value && (eventType == EventType.Repaint || eventType == EventType.Layout))
{
GUI.ScrollTo(element);
_scrollPosition.x = 0;
_scroll = -1;
}
if (element.Contains(Event.current.mousePosition))
{
if (Event.current.type == EventType.MouseMove ||
Event.current.type == EventType.ScrollWheel)
{
_hover = _filteredList.Entries[i].Value;
_keyboardIndex = i;
}
if (Event.current.type == EventType.MouseDown)
{
_onSelectionMade(_filteredList.Entries[i].Value);
EditorWindow.focusedWindow.Close();
}
}
DrawElement(element, _filteredList.Entries[i].Value, i);
element.y = element.yMax;
}
GUI.EndScrollView();
}
private void DrawElement(Rect rect, int value, int index)
{
if (value == _current)
{
DrawBox(rect, _selectedTexture, _selectedCircleTexture);
rect.xMin += _selectedCircleTexture.width * 2f;
}
else if (value == _hover)
{
DrawBox(rect, _hoverTexture);
}
GUI.Label(rect, _filteredList.Entries[index].Content, _elementStyle);
}
private void DrawBox(Rect rect, Texture texture, Texture symbol = null)
{
GUI.DrawTexture(rect, texture);
if (symbol == null) return;
rect.xMin += symbol.width * 0.5f;
rect.y = rect.center.y - symbol.height * 0.5f + SymbolVerticalOffset;
rect.width = symbol.width;
rect.height = symbol.height;
GUI.DrawTexture(rect, symbol);
}
private void HandleKeyboardInput()
{
if (Event.current.isKey is false || Event.current.type != EventType.KeyDown) return;
var keyCode = Event.current.keyCode;
if (keyCode == KeyCode.Escape)
{
EditorWindow.focusedWindow.Close();
return;
}
if (keyCode == KeyCode.Return)
{
_onSelectionMade(_filteredList.Entries[_keyboardIndex].Value);
EditorWindow.focusedWindow.Close();
return;
}
if (keyCode == KeyCode.DownArrow)
{
_keyboardIndex = Mathf.Min(_filteredList.Entries.Count - 1, _keyboardIndex + 1);
_hover = _filteredList.Entries[_keyboardIndex].Value;
Event.current.Use();
_scroll = _hover;
}
else if (keyCode == KeyCode.UpArrow)
{
_keyboardIndex = Mathf.Max(0, _keyboardIndex - 1);
_hover = _filteredList.Entries[_keyboardIndex].Value;
GUIUtility.hotControl = 0;
Event.current.Use();
_scroll = _hover;
}
}
#region Helpers
public static Rect Shrink(Rect rect, float amount)
{
return new Rect(rect.x + amount, rect.y + amount, rect.width - amount * 2, rect.height - amount * 2);
}
public static Texture SmallTexture(string hex)
{
Texture2D texture = new Texture2D(4, 4);
var color = HexToRGB(hex);
for (int i = 0; i < texture.width; i++)
{
for (int j = 0; j < texture.height; j++)
{
texture.SetPixel(i, j, color);
}
}
texture.Apply();
return texture;
}
public static Texture SmallTexture(Color color)
{
Texture2D texture = new Texture2D(4, 4);
for (int i = 0; i < texture.width; i++)
{
for (int j = 0; j < texture.height; j++)
{
texture.SetPixel(i, j, color);
}
}
texture.Apply();
return texture;
}
public static Texture DrawCircle(int radius, string hex)
{
Texture2D texture = new Texture2D(radius * 2, radius * 2);
var color = HexToRGB(hex);
float cX = radius;
float cY = radius;
float sizeSquared = radius * radius;
for (int i = 0; i < texture.width; i++)
{
for (int j = 0; j < texture.height; j++)
{
if ((cX - i) * (cX - i) + (cY - j) * (cY - j) < sizeSquared)
{
texture.SetPixel(i, j, color);
}
else texture.SetPixel(i, j, Color.clear);
}
}
texture.Apply();
return texture;
}
public static Texture DrawCircle(int radius, Color color)
{
Texture2D texture = new Texture2D(radius * 2, radius * 2);
float cX = radius;
float cY = radius;
float sizeSquared = radius * radius;
for (int i = 0; i < texture.width; i++)
{
for (int j = 0; j < texture.height; j++)
{
if ((cX - i) * (cX - i) + (cY - j) * (cY - j) < sizeSquared)
{
texture.SetPixel(i, j, color);
}
else texture.SetPixel(i, j, Color.clear);
}
}
texture.Apply();
return texture;
}
public static Color HexToRGB(string hex)
{
hex = hex.TrimStart('#');
if (hex.Length != 6) return Color.black;
int r = Int16.Parse(hex.Substring(0, 2),
System.Globalization.NumberStyles.AllowHexSpecifier);
int g = Int16.Parse(hex.Substring(2, 2),
System.Globalization.NumberStyles.AllowHexSpecifier);
int b = Int16.Parse(hex.Substring(4, 2),
System.Globalization.NumberStyles.AllowHexSpecifier);
return new Color(r / 255f, g / 255f, b / 255f);
}
public static string TextfieldWithTooltip(Rect rect, string text, string tooltip,
GUIStyle textfieldStyle, GUIStyle tooltipStyle)
{
text = GUI.TextField(rect, text, textfieldStyle);
if (text.Length == 0)
GUI.Label(rect, tooltip, tooltipStyle);
return text;
}
#endregion
}
I will be realy glad to see some advices or straight anwsers on this problem is someone can solve it :)
Thank you!
The problem
I am trying to procedurally generate dungeon rooms with random X, Y sizes inside of a radius (r). However, even after I validate that the starting grid (origin of the "room") is not in the same position as other origins after running the separation function there are rooms still building inside of each other.
Solutions I have tried
I tried using math to calculate an optimal radius that will be able to fit the average of all the room sizes * amount of rooms. However, the separation should hypothetically work with any radius (though I want to keep them relatively close in order to keep hallways short).
Code
All my code is based on one tile. This means that all calculations are using one tile, and will remain one tile until the very end, then I scale them up.
private void GenerateRooms(int amount)
{
// init sizes
Vector2[] room_sizes = new Vector2[amount];
for (int i = 0; i < amount; i++)
{
room_sizes[i] = new Vector2(Random.Range(minimum_room_height, maximum_room_height), Random.Range(minimum_room_width, maximum_room_width));
}
float biggest_room = calculations.CalculateBiggest(room_sizes);
Vector2[] room_points = new Vector2[amount];
Vector2[] used_points = new Vector2[amount];
float radius = calculations.CalculateAverage(room_sizes) * amount;
for (int i = 0; i < amount; i++)
{
do {
Vector2 test_point = new Vector2(Random.Range(-radius, radius), Random.Range(-radius, radius));
foreach (Vector2 point in used_points) {
if (test_point == point) {
continue;
} else {
room_points[i] = test_point;
used_points[i] = test_point;
break;
}
}
} while (Vector2.Distance(Vector2.zero, room_points[i]) < radius);
}
for (int i = 0; i < amount; i++)
{
//Vector2 origin = room_points[i];
Vector3 position = calculations.computeSeperate(room_points, room_points[i], biggest_room);
//position = new Vector3(position.x + origin.x, position.y + origin.y, 0);
Vector3Int location = tile_map.WorldToCell(position);
tile_map.SetTile(location, tile);
calculations.scaleUpRooms(position, room_sizes[i].x, room_sizes[i].y, tile_map, tile);
}
}
The above is code for calling all the functions and validating the points. Here are the important functions (calculation functions):
public Vector2 computeSeperate(Vector2[] point_array, Vector2 target_point, float minimum_distance)
{
int neighbor_count = 0;
for (int i = 0; i < point_array.Length; i++)
{
if (point_array[i] != target_point)
{
if (Vector2.Distance(target_point, point_array[i]) < minimum_distance * 2)
{
target_point.x += point_array[i].x - target_point.x;
target_point.y += point_array[i].y - target_point.y;
neighbor_count++;
}
}
}
if (neighbor_count == 0)
{
return target_point;
} else
{
target_point.x /= neighbor_count;
target_point.y /= neighbor_count;
target_point.x *= -1;
target_point.y *= -1;
target_point.Normalize();
return target_point;
}
}
public void scaleUpRooms(Vector2 base_point, float scale_x, float scale_y, Tilemap tile_map, Tile tile) // ex: 5x5
{
List<Vector2> Calculate(Vector2 size)
{
List<Vector2> results = new List<Vector2>();
for (int i = 0; i < size.y; i++)
for (int o = 0; o < size.x; o++)
results.Add(new Vector2(o, i) + (new Vector2(size.x % 2 != 0 ? .5f : 1, size.y % 2 != 0 ? .5f : 1) - (size / 2)));
string st = "";
for (int i = 0; i < results.Count; i++)
st += "\n" + results[i].ToString();
return results;
}
Vector2 desired_scale = new Vector2(scale_x, scale_y);
List<Vector2> Offsets = Calculate(desired_scale);
for (int i = 0; i < Offsets.Count; i++)
{
Vector3 position = base_point + Offsets[i];
Vector3Int location = tile_map.WorldToCell(position);
tile_map.SetTile(location, tile);
}
}
I'm trying to do a fade between two colors on a weather system in C#. I'm using the following code to fade the color of the keys of a gradient used by the clouds:
void ChangeWeather(string to)
{
Gradient g = skyController.WispyColorGradientColor[0];
GradientColorKey[] gck = new GradientColorKey[5];
GradientAlphaKey[] gak = new GradientAlphaKey[2];
gak[0].alpha = 1f;
gak[1].alpha = 1f;
gak[0].time = 0f;
gak[1].time = 100f;
Color color = new Color();
skyController.WispyColorGradientColor[0] = g;
//Set the initial value
gck[0] = g.colorKeys[0];
gck[1] = g.colorKeys[1];
gck[2] = g.colorKeys[2];
gck[3] = g.colorKeys[3];
gck[4] = g.colorKeys[4];
//refer te variables
g.colorKeys[0] = gck[0];
g.colorKeys[1] = gck[1];
g.colorKeys[2] = gck[2];
g.colorKeys[3] = gck[3];
g.colorKeys[4] = gck[4];
//set the times
gck[0].time = .209f;
gck[1].time = .238f;
gck[2].time = .50f;
gck[3].time = .756f;
gck[4].time = .791f;
if (to == "clear")
{
ColorUtility.TryParseHtmlString(cleanCloudsColors[0], out color);
gck[0].color = Color.Lerp(g.colorKeys[0].color, color, changeSpeed * Time.deltaTime);
gck[4].color = Color.Lerp(g.colorKeys[4].color, color, changeSpeed * Time.deltaTime);
ColorUtility.TryParseHtmlString(cleanCloudsColors[1], out color);
gck[1].color = Color.Lerp(g.colorKeys[1].color, color, changeSpeed * Time.deltaTime);
gck[3].color = Color.Lerp(g.colorKeys[3].color, color, changeSpeed * Time.deltaTime);
ColorUtility.TryParseHtmlString(cleanCloudsColors[2], out color);
gck[2].color = Color.Lerp(g.colorKeys[2].color, color, changeSpeed * Time.deltaTime);
Debug.Log("Changing");
}
}
The "skyController.WispyColorGradientColor[0]" refers to a Gradient in a array list and "ColorUtility.TryParseHtmlString" just convert a hex color (like #fff) to RGB. It log "Changing" but, well, the clouds were changing color without fade, so I made these changes and it does not change more. I NEED THE FADE, but nothing seems to work. :(
EDIT: I used a code like it to try to fade between colors in 5 seconds:
float fadeTime = 5f;
void Update(){
//...
if (param)
StartCoroutine(fadeColor(0, Color.grey, Color.white));
//...
}
IEnumerator fadeColor (int index, Color from, Color to){
float counter = 0;
while (counter < fadeTime){
counter += Time.deltaTime;
gradient.colorKeys[index].color = Color.Lerp(from, to, counter / fadeTime);
}
yield return null;
}
It change the color, but change instantly and I want to change over time.
Not able to understand your code and but all I know is that you want to fade between two Colors. This should be done with Coroutine. The function below should fade between two colors in any GameObject. You can easily modify it to suit whatever you are doing.
The function call below will change the GameObject's color to red in 5 seconds.
StartCoroutine(fadeColor(obj, Color.red, 5));
Fade Function:
IEnumerator fadeColor(GameObject objectToFade, Color newColor, float fadeTime = 3)
{
int mode = 0;
Color currentColor = Color.clear;
SpriteRenderer tempSPRenderer = objectToFade.GetComponent<SpriteRenderer>();
Image tempImage = objectToFade.GetComponent<Image>();
RawImage tempRawImage = objectToFade.GetComponent<RawImage>();
Renderer tempRenderer = objectToFade.GetComponent<Renderer>();
//Check if this is a Sprite
if (tempSPRenderer != null)
{
currentColor = tempSPRenderer.color;
mode = 0;
}
//Check if Image
else if (tempImage != null)
{
currentColor = tempImage.color;
mode = 1;
}
//Check if RawImage
else if (tempRawImage != null)
{
currentColor = tempRawImage.color;
mode = 2;
}
//Check if 3D Object
else if (tempRenderer != null)
{
currentColor = tempRenderer.material.color;
mode = 3;
}
else
{
yield break;
}
float counter = 0;
while (counter < fadeTime)
{
counter += Time.deltaTime;
switch (mode)
{
case 0:
tempSPRenderer.color = Color.Lerp(currentColor, newColor, counter / fadeTime);
break;
case 1:
tempImage.color = Color.Lerp(currentColor, newColor, counter / fadeTime);
break;
case 2:
tempRawImage.color = Color.Lerp(currentColor, newColor, counter / fadeTime);
break;
case 3:
tempRenderer.material.color = Color.Lerp(currentColor, newColor, counter / fadeTime);
break;
}
yield return null;
}
}
I'm building a game using xna and I've created a terrain using VertexElementNormalTexture. I understand I can add position, the normal and texture coordinates to the vertex element but is there anyway to add which texture I want to use. I'm testing it on my Lumia phone so it's being built without the use of custom shaders because they're unsupported by the phone making most of the tutorials on the web out of date. I believe the basiceffects only support one texture per effect so if I make a number of effects how do I get the vertex to know which effect to use? the grasseffect, watereffect, etc.
The code I've got so far is below.
Thank you.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
using Microsoft.Devices.Sensors;
namespace WindowsPhoneGame2
{
public class Game1 : Microsoft.Xna.Framework.Game
{
#region // Variables
public struct VertexPositionColorNormal
{
public Vector3 Position;
public Color Color;
public Vector3 Normal;
public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration
(
new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
new VertexElement(sizeof(float) * 3, VertexElementFormat.Color, VertexElementUsage.Color, 0),
new VertexElement(sizeof(float) * 3 + 4, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0)
);
}
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
RasterizerState rasterizerState;
// terrain
BasicEffect grassEffect;
Texture2D grassTexture;
BasicEffect waterEffect;
Texture2D waterTexture;
VertexDeclaration vertexDeclaration;
VertexPositionNormalTexture[] vertices;
short[] indices;
VertexBuffer myVertexBuffer;
IndexBuffer myIndexBuffer;
private float[,] heightData;
private int terrainWidth;
private int terrainLength;
int nScale = 16;
Vector3 terrainPosition;
Texture2D heightMap;
Matrix viewMatrix;
Matrix projectionMatrix;
Matrix worldMatrix;
// aircraft model
private Model aircraftModel;
private Vector3 aircraftPosition;
Matrix aircraftMatrix;
// shell model
private Model shellModel;
private Vector3 bulletPosition;
Matrix bulletMatrix;
bool blBulletFiring;
private Vector3 torpedoPosition;
Matrix torpedoMatrix;
bool blTorpedoFiring;
float nTorpedoScale;
// display
private SpriteFont font;
float nHeightData;
int nBullets = 0;
int nTorpedoes = 0;
// tilt gesture
private float rollAngle;
private float pitchAngle;
private float yawAngle;
Accelerometer accelerometer;
private const int _num = 5;
private double[] _y = new double[_num];
private int _index = 0;
private const int _num2 = 5;
private double[] _y2 = new double[_num2];
private int _index2 = 0;
Texture2D explosionTexture;
List<ParticleData> particleList = new List<ParticleData>();
public struct ParticleData
{
public float BirthTime;
public float MaxAge;
public Vector2 OrginalPosition;
public Vector2 Accelaration;
public Vector2 Direction;
public Vector2 Position;
public float Scaling;
public Color ModColor;
}
Random random = new Random();
#endregion
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
TouchPanel.EnabledGestures = GestureType.Tap | GestureType.Hold;
loadTextures();
loadAccelerometer();
loadCamera();
loadEffect();
loadTerrain();
}
protected override void UnloadContent()
{
}
private void loadTextures()
{
aircraftModel = Content.Load<Model>("Ship");
shellModel = Content.Load<Model>("Shell");
explosionTexture = Content.Load<Texture2D>("explosion");
heightMap = Content.Load<Texture2D>("heightmap");
grassTexture = Content.Load<Texture2D>("Grass");
waterTexture = Content.Load<Texture2D>("Water");
font = Content.Load<SpriteFont>("DisplayText");
}
private void loadAccelerometer()
{
rollAngle = 0;
if (accelerometer == null)
{
accelerometer = new Accelerometer();
accelerometer.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);
accelerometer.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<AccelerometerReading>>(accelerometer_CurrentValueChanged);
}
accelerometer.Start();
}
private void loadCamera()
{
aircraftPosition = new Vector3(heightMap.Width * nScale * 2 / 2, 0, 400);
projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, graphics.GraphicsDevice.Viewport.AspectRatio, 10.0f, 8000.0f);
worldMatrix = Matrix.CreateTranslation(0, 0, 0);
terrainPosition = new Vector3(0, 0, 0);
}
private void loadEffect()
{
//grass effect
grassEffect = new BasicEffect(GraphicsDevice);
//grassEffect.VertexColorEnabled = true;
grassEffect.LightingEnabled = true; // Turn on the lighting subsystem.
grassEffect.DirectionalLight0.DiffuseColor = new Vector3(0.1f, 0.1f, 0.1f);
grassEffect.DirectionalLight0.Direction = new Vector3(0, 5, -10);
grassEffect.TextureEnabled = true;
grassEffect.Texture = grassTexture;
//water effect
waterEffect = new BasicEffect(GraphicsDevice);
waterEffect.LightingEnabled = true; // Turn on the lighting subsystem.
waterEffect.DirectionalLight0.DiffuseColor = new Vector3(0.1f, 0.1f, 0.1f);
waterEffect.DirectionalLight0.Direction = new Vector3(0, 5, -10);
waterEffect.TextureEnabled = true;
waterEffect.Texture = waterTexture;
}
private void loadTerrain()
{
LoadHeightData();
SetUpVertices();
SetUpIndices();
CalculateNormals();
CopyToBuffers();
}
private void LoadHeightData()
{
terrainWidth = heightMap.Width;
terrainLength = heightMap.Height;
Color[] heightMapColors = new Color[terrainWidth * terrainLength];
heightMap.GetData(heightMapColors);
heightData = new float[terrainWidth, terrainLength];
for (int x = 0; x < terrainWidth; x++)
for (int y = 0; y < terrainLength; y++)
heightData[x, y] = heightMapColors[x + y * terrainWidth].R / 5.0f;
}
private void SetUpVertices()
{
vertices = new VertexPositionNormalTexture[terrainWidth * terrainLength];
for (int x = 0; x < terrainWidth; x++)
{
for (int y = 0; y < terrainLength; y++)
{
vertices[x + y * terrainWidth].Position = new Vector3(x * nScale * 2, y * nScale, heightData[x, y] * nScale) + terrainPosition;
}
}
}
private void SetUpIndices()
{
indices = new short[(terrainWidth - 1) * (terrainLength - 1) * 6];
int counter = 0;
for (int y = 0; y < terrainLength - 1; y++)
{
for (int x = 0; x < terrainWidth - 1; x++)
{
short lowerLeft = (short)(x + y * terrainWidth);
short lowerRight = (short)((x + 1) + y * terrainWidth);
short topLeft = (short)(x + (y + 1) * terrainWidth);
short topRight = (short)((x + 1) + (y + 1) * terrainWidth);
indices[counter++] = topLeft;
indices[counter++] = lowerRight;
indices[counter++] = lowerLeft;
indices[counter++] = topLeft;
indices[counter++] = topRight;
indices[counter++] = lowerRight;
}
}
}
private void CalculateNormals()
{
for (int i = 0; i < vertices.Length; i++)
vertices[i].Normal = new Vector3(0, 0, 0);
for (int i = 0; i < indices.Length / 3; i++)
{
int index1 = indices[i * 3];
int index2 = indices[i * 3 + 1];
int index3 = indices[i * 3 + 2];
Vector3 side1 = vertices[index1].Position - vertices[index3].Position;
Vector3 side2 = vertices[index1].Position - vertices[index2].Position;
Vector3 normal = Vector3.Cross(side1, side2);
vertices[index1].Normal += normal;
vertices[index2].Normal += normal;
vertices[index3].Normal += normal;
}
for (int i = 0; i < vertices.Length; i++)
vertices[i].Normal.Normalize();
}
private void CopyToBuffers()
{
myVertexBuffer = new VertexBuffer(graphics.GraphicsDevice, VertexPositionNormalTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
myVertexBuffer.SetData(vertices);
myIndexBuffer = new IndexBuffer(graphics.GraphicsDevice, typeof(short), indices.Length, BufferUsage.WriteOnly);
myIndexBuffer.SetData(indices);
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// Adjust camera position
viewMatrix = Matrix.CreateLookAt(new Vector3(aircraftPosition.X, aircraftPosition.Y - 10, aircraftPosition.Z + 5), new Vector3(aircraftPosition.X, aircraftPosition.Y + 5, aircraftPosition.Z ), new Vector3(0, 1, 0));
// Adjust aircraft position
aircraftMatrix = Matrix.CreateRotationY(rollAngle) * Matrix.CreateRotationX(pitchAngle) * Matrix.CreateRotationZ(yawAngle) * Matrix.CreateTranslation(aircraftPosition);
aircraftPosition.Y += 10.0f;
// Check against height data for collision
int x = (int)aircraftPosition.X / (nScale * 2);
int y = ((int)aircraftPosition.Y - (int)terrainPosition.Y) / nScale;
if(y < 128) nHeightData = heightData[(int)x, (int)y];
if (nHeightData > aircraftPosition.Z / nScale)
{
aircraftPosition = new Vector3(terrainWidth * nScale * 2 / 2, 0, 400);
terrainPosition = new Vector3(0, 0, 0);
}
// edit weapons fire positions
if (blBulletFiring)
{
bulletPosition.Y += 20;
fireBullet();
}
if (blTorpedoFiring)
{
if (torpedoPosition.Z > 5)
{
torpedoPosition.Z -= 6;
torpedoPosition.Y += 10;
nTorpedoScale = 0.8f;
}
else
{
torpedoPosition.Y += 16;
nTorpedoScale = 1.5f;
}
fireTorpedo();
}
// detect any gestures
while (TouchPanel.IsGestureAvailable)
{
GestureSample gs = TouchPanel.ReadGesture();
switch (gs.GestureType)
{
case GestureType.Tap:
blBulletFiring = true;
bulletPosition = new Vector3(aircraftPosition.X - 0.05f, aircraftPosition.Y, aircraftPosition.Z);
AddExplosion(new Vector2(gs.Position.X, gs.Position.Y), 12, 80.0f, 1500.0f, gameTime);
// AddExplosion(new Vector2(aircraftPosition.X * -1, aircraftPosition.Y * -1), 12, 80.0f, 1500.0f, gameTime);
break;
case GestureType.Hold:
blTorpedoFiring = true;
torpedoPosition = new Vector3(aircraftPosition.X, aircraftPosition.Y, aircraftPosition.Z);
break;
}
}
if (particleList.Count > 0)
UpdateParticles(gameTime);
base.Update(gameTime);
}
private void UpdateParticles(GameTime gameTime)
{
float now = (float)gameTime.TotalGameTime.TotalMilliseconds;
for (int i = particleList.Count - 1; i >= 0; i--)
{
ParticleData particle = particleList[i];
float timeAlive = now - particle.BirthTime;
if (timeAlive > particle.MaxAge)
{
particleList.RemoveAt(i);
}
else
{
float relAge = timeAlive / particle.MaxAge;
particle.Position = 0.5f * particle.Accelaration * relAge * relAge + particle.Direction * relAge + particle.OrginalPosition;
float invAge = 1.0f - relAge;
particle.ModColor = new Color(new Vector4(invAge, invAge, invAge, invAge));
Vector2 positionFromCenter = particle.Position - particle.OrginalPosition;
float distance = positionFromCenter.Length();
particle.Scaling = (50.0f + distance) / 200.0f;
particleList[i] = particle;
}
}
}
private void AddExplosion(Vector2 explosionPos, int numberOfParticles, float size, float maxAge, GameTime gameTime)
{
for (int i = 0; i < numberOfParticles; i++)
AddExplosionParticle(explosionPos, size, maxAge, gameTime);
}
private void AddExplosionParticle(Vector2 explosionPos, float explosionSize, float maxAge, GameTime gameTime)
{
ParticleData particle = new ParticleData();
particle.OrginalPosition = explosionPos;
particle.Position = particle.OrginalPosition;
particle.BirthTime = (float)gameTime.TotalGameTime.TotalMilliseconds;
particle.MaxAge = maxAge;
particle.Scaling = 0.25f;
particle.ModColor = Color.White;
float particleDistance = (float)random.NextDouble() * explosionSize;
Vector2 displacement = new Vector2(particleDistance, 0);
float angle = MathHelper.ToRadians(random.Next(360));
displacement = Vector2.Transform(displacement, Matrix.CreateRotationZ(angle));
particle.Direction = displacement * 2.0f;
particle.Accelaration = -particle.Direction;
particleList.Add(particle);
}
private void fireBullet()
{
nBullets++;
bulletMatrix = Matrix.CreateScale(0.1f) * Matrix.CreateRotationZ(MathHelper.ToRadians(90)) * Matrix.CreateTranslation(bulletPosition);
if (bulletPosition.Y > aircraftPosition.Y + 200)
{
blBulletFiring = false;
}
}
private void fireTorpedo()
{
nTorpedoes++;
torpedoMatrix = Matrix.CreateScale(nTorpedoScale) * Matrix.CreateRotationZ(MathHelper.ToRadians(90)) * Matrix.CreateTranslation(torpedoPosition);
if (torpedoPosition.Y > aircraftPosition.Y + 1000)
{
blTorpedoFiring = false;
}
}
public void accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e)
{
_y[_index++] = e.SensorReading.Acceleration.Y;
if (_index >= _num) _index = 0;
double ysum = 0.0;
for (int i = 0; i < _num; i++)
ysum += _y[i];
double x = ysum / _num;
// Cap it at -0.5 and 0.5
if (x > 0.1)
{
if (rollAngle >= -0.9)
{
rollAngle -= 0.05f;
yawAngle += 0.02f;
}
if (aircraftPosition.X >= 5) aircraftPosition.X -= rollAngle * -5;
}
else if (x <= -0.1)
{
if (rollAngle <= 0.9)
{
rollAngle += 0.05f;
yawAngle -= 0.02f;
}
if (aircraftPosition.X <= terrainWidth * nScale * 2 - 6) aircraftPosition.X += rollAngle * 5;
}
else
{
if (rollAngle > 0.05)
{
rollAngle -= 0.05f;
yawAngle += 0.02f;
}
else if (rollAngle < -0.05)
{
rollAngle += 0.05f;
yawAngle -= 0.02f;
}
else
{
rollAngle = 0;
yawAngle = 0;
}
}
_y2[_index2++] = e.SensorReading.Acceleration.X;
if (_index2 >= _num2) _index2 = 0;
double ysum2 = 0.0;
for (int i = 0; i < _num2; i++)
ysum2 += _y2[i];
double x2 = ysum2 / _num2;
// Cap it at -0.5 and 0.5
if (x2 > -0.4)
{
if(pitchAngle >= -0.6) pitchAngle -= 0.025f;
if (aircraftPosition.Z > 6) aircraftPosition.Z -= pitchAngle * -10;
}
else if (x2 <= -0.5)
{
if (pitchAngle <= 0.6) pitchAngle += 0.025f;
if (aircraftPosition.Z <= 500) aircraftPosition.Z += pitchAngle * 10;
}
else
{
if (pitchAngle > 0.05) pitchAngle -= 0.05f;
else if (pitchAngle < -0.05) pitchAngle += 0.05f;
else pitchAngle = 0;
}
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1.0f, 0);
GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
rasterizerState = new RasterizerState();
rasterizerState.FillMode = FillMode.Solid;
rasterizerState.CullMode = CullMode.None;
GraphicsDevice.RasterizerState = rasterizerState;
Vector3 oldPosition = terrainPosition;
loadTerrain();
DrawTerrain();
terrainPosition.Y += nScale * terrainLength - nScale;
loadTerrain();
DrawTerrain();
terrainPosition.Y += nScale * terrainLength - nScale;
loadTerrain();
DrawTerrain();
terrainPosition.Y -= nScale * terrainLength - nScale;
if (aircraftPosition.Y >= terrainPosition.Y)
{ }
else
{
terrainPosition = oldPosition;
}
if (blBulletFiring) DrawBullet(shellModel, bulletMatrix, viewMatrix, projectionMatrix);
if(blTorpedoFiring) DrawTorpedo(shellModel, torpedoMatrix, viewMatrix, projectionMatrix);
DrawAircraft(aircraftModel, aircraftMatrix, viewMatrix, projectionMatrix);
DrawDisplay();
DrawExplosion();
base.Draw(gameTime);
}
private void DrawTerrain()
{
grassEffect.World = worldMatrix;
grassEffect.View = viewMatrix;
grassEffect.Projection = projectionMatrix;
foreach (EffectPass pass in grassEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.Indices = myIndexBuffer;
GraphicsDevice.SetVertexBuffer(myVertexBuffer);
GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indices, 0, indices.Length / 3);
}
}
private void DrawBullet(Model model, Matrix world, Matrix view, Matrix projection)
{
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.LightingEnabled = true;
effect.DirectionalLight0.DiffuseColor = new Vector3(0.9f, 0.0f, 0.0f);
effect.DirectionalLight0.Direction = new Vector3(0, 1, -1);
effect.World = world;
effect.View = view;
effect.Projection = projection;
}
mesh.Draw();
}
}
private void DrawTorpedo(Model model, Matrix world, Matrix view, Matrix projection)
{
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.LightingEnabled = true;
effect.DirectionalLight0.DiffuseColor = new Vector3(0.0f, 0.0f, 0.0f);
effect.DirectionalLight0.Direction = new Vector3(0, 1, -1);
effect.World = world;
effect.View = view;
effect.Projection = projection;
}
mesh.Draw();
}
}
private void DrawAircraft(Model model, Matrix world, Matrix view, Matrix projection)
{
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
// effect.EnableDefaultLighting();
effect.LightingEnabled = true; // Turn on the lighting subsystem.
effect.DirectionalLight0.DiffuseColor = new Vector3(0.2f, 0.2f, 0.2f);
effect.DirectionalLight0.Direction = new Vector3(0, 5, -10);
//effect.DirectionalLight0.SpecularColor = new Vector3(0, 1, 0); // with green highlights
//effect.AmbientLightColor = new Vector3(0.2f, 0.2f, 0.2f); // Add some overall ambient light.
//effect.EmissiveColor = new Vector3(1, 0, 0); // Sets some strange emmissive lighting. This just looks weird.
effect.World = world;
effect.View = view;
effect.Projection = projection;
}
mesh.Draw();
}
}
private void DrawDisplay()
{
spriteBatch.Begin();
spriteBatch.DrawString(font, "Position: " + aircraftPosition.ToString(), new Vector2(10, 10), Color.Black);
spriteBatch.DrawString(font, "Ground Height: " + nHeightData.ToString(), new Vector2(10, 25), Color.Black);
spriteBatch.DrawString(font, "Bullet Position: " + nBullets.ToString(), new Vector2(10, 40), Color.Black);
spriteBatch.DrawString(font, "Torpedo Position: " + nTorpedoes.ToString(), new Vector2(10, 55), Color.Black);
spriteBatch.End();
}
private void DrawExplosion()
{
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive);
for (int i = 0; i < particleList.Count; i++)
{
ParticleData particle = particleList[i];
spriteBatch.Draw(explosionTexture, particle.Position, null, particle.ModColor, i, new Vector2(256, 256), particle.Scaling, SpriteEffects.None, 1);
}
spriteBatch.End();
}
}
}
Instead of using a BasicEffect, use a DualTextureEffect. I've never used it before because I don't develop for hone but this is supposed to be a very good tutorial. http://blogs.msdn.com/b/shawnhar/archive/2010/08/04/dualtextureeffect.aspx>
So I have a script that shoots an arrow when you click and drag, kinda like Angry Birds.
I want it to work with the 2D RigidBody and 2D collider but when I change the rigidbody.AddForce to rigidbody2D.AddForce, It doesn't work.
How can I fix this to work for 2D?
I also want the arrow to rotate in 2D space either up or down depending on where mouse is pulled back. When I try the mouse look script, it rotates it in the z axis (I think) and distorts the arrow. Any easy solution to fix this??
Thanks guys. I'm new to game making and I've been trying to figure this stuff out for like the last 10 hours. I need some pros to help!
Thanks!!!
Heres my script
using UnityEngine;
using System.Collections;
public class DragShotMover2 : MonoBehaviour {
public float maxDragLength = 2; // this is the base magnitude and the maximum length of the line drawn in the user interface
public float maxMultiplier = 5; // multiply the line length by this to allow for higher force values to be represented by shorter lines
public Vector3 dragPlaneNormal = Vector3.up; // a vector describing the orientation of the drag plan relative to world-space but centered on the target
public SnapDir snapDirection = SnapDir.away; // force is applied either toward or away from the mouse on release
public ForceMode forceTypeToApply = ForceMode.VelocityChange;
public bool overrideVelocity = true; // cancel the existing velocity before applying the new force
public bool pauseOnDrag = true; // causes the simulation to pause when the object is clicked and unpause when released
public Color noForceColor = Color.yellow; // color of the visualization helpers at force 0
public Color maxForceColor = Color.red; // color of the visualization helpers at maximum force
public enum SnapDir {toward, away}
private Vector3 forceVector;
private float magPercent = 0;
private bool mouseDragging = false;
private Vector3 mousePos3D;
private float dragDistance;
private Plane dragPlane;
private Ray mouseRay;
private GameObject dragZone;
private string shaderString = "Transparent/Diffuse";
private Material dzMat;
void Start (){
Color currentColor = noForceColor;
dzMat = new Material(Shader.Find(shaderString));
// create the dragzone visual helper
dragZone = new GameObject("dragZone_" + gameObject.name);
dragZone.AddComponent<MeshFilter>().mesh = MakeDiscMeshBrute(maxDragLength/4);
//dragZone.GetComponent.MeshFilter.
dragZone.AddComponent<MeshRenderer>();
dragZone.renderer.enabled = false;
dragZone.name = "dragZone_" + gameObject.name;
dragZone.transform.localScale = new Vector3(maxDragLength*2, 0.025f, maxDragLength*2);
dragZone.renderer.material = dzMat;
dragZone.renderer.material.color = currentColor * new Color(1,1,1,0.2f);
// create the dragplane
dragPlane = new Plane(dragPlaneNormal, transform.position);
// orient the drag plane
if (dragPlaneNormal != Vector3.zero) {
dragZone.transform.rotation = Quaternion.LookRotation(dragPlaneNormal) * new Quaternion(1, 0, 0, 1);
}
else Debug.LogError("Drag plane normal cannot be equal to Vector3.zero.");
//update the position of the dragzone
dragZone.transform.position = transform.position;
}
void OnMouseDown (){
mouseDragging = true;
if (pauseOnDrag) {
// pause the simulation
Time.timeScale = 0;
}
// update the dragplane
dragPlane = new Plane(dragPlaneNormal, transform.position);
// orient the drag plane
if (dragPlaneNormal != Vector3.zero) {
dragZone.transform.rotation = Quaternion.LookRotation(dragPlaneNormal) * new Quaternion(1, 0, 0, 1);
}
else Debug.LogError("Drag plane normal cannot be equal to Vector3.zero.");
//update the position of the dragzone
dragZone.transform.position = transform.position;
dragZone.renderer.enabled = true;
}
void OnMouseDrag (){
Color currentColor = noForceColor;
// update the plane if the target object has left it
if (dragPlane.GetDistanceToPoint(transform.position) != 0) {
// update dragplane by constructing a new one -- I should check this with a profiler
dragPlane = new Plane(dragPlaneNormal, transform.position);
}
// create a ray from the camera, through the mouse position in 3D space
mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
// if mouseRay intersects with dragPlane
float intersectDist = 0.0f;
if (dragPlane.Raycast(mouseRay, out intersectDist)) {
// update the world space point for the mouse position on the dragPlane
mousePos3D = mouseRay.GetPoint(intersectDist);
// calculate the distance between the 3d mouse position and the object position
dragDistance = Mathf.Clamp((mousePos3D - transform.position).magnitude, 0, maxDragLength);
// calculate the force vector
if (dragDistance*maxMultiplier < 1) dragDistance = 0; // this is to allow for a "no move" buffer close to the object
forceVector = mousePos3D - transform.position;
forceVector.Normalize();
forceVector *= dragDistance * maxMultiplier;
// update color the color
// calculate the percentage value of current force magnitude out of maximum
magPercent = (dragDistance * maxMultiplier) / (maxDragLength * maxMultiplier);
// choose color based on how close magPercent is to either 0 or max
currentColor = noForceColor * (1-magPercent) + maxForceColor * magPercent;
// dragzone color
dragZone.renderer.material.color = currentColor * new Color(1,1,1,0.2f);
// draw the line
Debug.DrawRay(transform.position, forceVector / maxMultiplier, currentColor);
}
//update the position of the dragzone
dragZone.transform.position = transform.position;
}
void OnMouseUp (){
mouseDragging = false;
if (overrideVelocity) {
// cancel existing velocity
rigidbody.AddForce(-rigidbody.velocity, ForceMode.VelocityChange);
}
// add new force
int snapD = 1;
if (snapDirection == SnapDir.away) snapD = -1; // if snapdirection is "away" set the force to apply in the opposite direction
rigidbody.AddForce(snapD * forceVector, forceTypeToApply);
// cleanup
dragZone.renderer.enabled = false;
if (pauseOnDrag) {
// un-pause the simulation
Time.timeScale = 1;
}
}
void OnGUI (){
if (mouseDragging) {
Vector2 guiMouseCoord = GUIUtility.ScreenToGUIPoint(Input.mousePosition);
GUI.Box ( new Rect(guiMouseCoord.x-30, Screen.height-guiMouseCoord.y+15, 100, 20), "force: "+Mathf.Round((forceVector).magnitude));
}
}
Mesh MakeDiscMeshBrute ( float r ){
Mesh discMesh;
Vector3[] dmVerts = new Vector3[18];
Vector3[] dmNorms = new Vector3[18];
Vector2[] dmUVs = new Vector2[18];
int[] dmTris = new int[48];
int i = 0;
discMesh = new Mesh();
dmVerts[0] = new Vector3(0,0,0);
dmVerts[1] = new Vector3(0,0,r);
dmVerts[2] = new Vector3(1,0,1).normalized * r; // find the vector at the correct distance the hacky-hillbilly way!
dmVerts[3] = new Vector3(r,0,0);
dmVerts[4] = new Vector3(1,0,-1).normalized * r;
dmVerts[5] = new Vector3(0,0,-r);
dmVerts[6] = new Vector3(-1,0,-1).normalized * r;
dmVerts[7] = new Vector3(-r,0,0);
dmVerts[8] = new Vector3(-1,0,1).normalized * r;
// set the other side to the same points
for (i = 0; i<dmVerts.Length/2; i++) {
dmVerts[dmVerts.Length/2 + i] = dmVerts[i];
}
for (i = 0; i<dmNorms.Length; i++) {
if (i<dmNorms.Length/2) dmNorms[i] = Vector3.up; // set side one to face up
else dmNorms[i] = -Vector3.up; // set side two to face down
}
dmUVs[0] = new Vector2(0,0);
dmUVs[1] = new Vector2(0,r);
dmUVs[2] = new Vector2(1,1).normalized * r;;
dmUVs[3] = new Vector2(r,0);
dmUVs[4] = new Vector2(1,-1).normalized * r;;
dmUVs[5] = new Vector2(0,-r);
dmUVs[6] = new Vector2(-1,-1).normalized * r;;
dmUVs[7] = new Vector2(-r,0);
dmUVs[8] = new Vector2(-1,1).normalized * r;;
// set the other side to the same points
for (i = 0; i<dmUVs.Length/2; i++) {
dmUVs[dmUVs.Length/2 + i] = dmUVs[i];
}
dmTris[0] = 0;
dmTris[1] = 1;
dmTris[2] = 2;
dmTris[3] = 0;
dmTris[4] = 2;
dmTris[5] = 3;
dmTris[6] = 0;
dmTris[7] = 3;
dmTris[8] = 4;
dmTris[9] = 0;
dmTris[10] = 4;
dmTris[11] = 5;
dmTris[12] = 0;
dmTris[13] = 5;
dmTris[14] = 6;
dmTris[15] = 0;
dmTris[16] = 6;
dmTris[17] = 7;
dmTris[18] = 0;
dmTris[19] = 7;
dmTris[20] = 8;
dmTris[21] = 0;
dmTris[22] = 8;
dmTris[23] = 1;
// side two
dmTris[24] = 9;
dmTris[25] = 11;
dmTris[26] = 10;
dmTris[27] = 9;
dmTris[28] = 12;
dmTris[29] = 11;
dmTris[30] = 9;
dmTris[31] = 13;
dmTris[32] = 12;
dmTris[33] = 9;
dmTris[34] = 14;
dmTris[35] = 13;
dmTris[36] = 9;
dmTris[37] = 15;
dmTris[38] = 14;
dmTris[39] = 9;
dmTris[40] = 16;
dmTris[41] = 15;
dmTris[42] = 9;
dmTris[43] = 17;
dmTris[44] = 16;
dmTris[45] = 9;
dmTris[46] = 10;
dmTris[47] = 17;
discMesh.vertices = dmVerts;
discMesh.uv = dmUVs;
discMesh.normals = dmNorms;
discMesh.triangles = dmTris;
return discMesh;
}
}
If you want to keep using the 3D Rigidbody, I'd suggest just using RigidbodyConstraints, so you can lock the z (or whatever) axis/rotation, and it will perform exactly the same as a 2D platformer.