Replace square with cone for Basic Arrow Tower.
This commit is contained in:
parent
90fd1c23d3
commit
430e66bfbf
7 changed files with 167 additions and 6 deletions
|
|
@ -10,11 +10,11 @@ MonoBehaviour:
|
||||||
m_Enabled: 1
|
m_Enabled: 1
|
||||||
m_EditorHideFlags: 0
|
m_EditorHideFlags: 0
|
||||||
m_Script: {fileID: 11500000, guid: 7b353a757b6e6774d97e6fb8ba138fcc, type: 3}
|
m_Script: {fileID: 11500000, guid: 7b353a757b6e6774d97e6fb8ba138fcc, type: 3}
|
||||||
m_Name: BasicTower
|
m_Name: BasicArrowTower
|
||||||
m_EditorClassIdentifier: Assembly-CSharp::TD.Towers.TowerDefinition
|
m_EditorClassIdentifier: Assembly-CSharp::TD.Towers.TowerDefinition
|
||||||
DisplayName: Basic Arrow
|
DisplayName: Basic Arrow Tower
|
||||||
Description: Targets ground and air. Fires single-target arrows. The bread and butter
|
Description: Single-target tower that fires arrows at ground and air enemies. The
|
||||||
of any maze.
|
backbone of any maze.
|
||||||
FootprintSize: {x: 2, y: 2}
|
FootprintSize: {x: 2, y: 2}
|
||||||
GoldCost: 25
|
GoldCost: 25
|
||||||
BuildTime: 0.5
|
BuildTime: 0.5
|
||||||
|
|
@ -69,8 +69,9 @@ GameObject:
|
||||||
- component: {fileID: 9137031893466587143}
|
- component: {fileID: 9137031893466587143}
|
||||||
- component: {fileID: 805962841523123163}
|
- component: {fileID: 805962841523123163}
|
||||||
- component: {fileID: 8853488620519990682}
|
- component: {fileID: 8853488620519990682}
|
||||||
|
- component: {fileID: 5360241685303413177}
|
||||||
m_Layer: 0
|
m_Layer: 0
|
||||||
m_Name: Tower_Basic
|
m_Name: Tower_BasicArrow
|
||||||
m_TagString: Untagged
|
m_TagString: Untagged
|
||||||
m_Icon: {fileID: 0}
|
m_Icon: {fileID: 0}
|
||||||
m_NavMeshLayer: 0
|
m_NavMeshLayer: 0
|
||||||
|
|
@ -100,7 +101,7 @@ MeshFilter:
|
||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 6482414459531823157}
|
m_GameObject: {fileID: 6482414459531823157}
|
||||||
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
m_Mesh: {fileID: 0}
|
||||||
--- !u!23 &4028055828417179692
|
--- !u!23 &4028055828417179692
|
||||||
MeshRenderer:
|
MeshRenderer:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
@ -241,6 +242,21 @@ MonoBehaviour:
|
||||||
m_EditorClassIdentifier: Assembly-CSharp::TD.Combat.TowerRangeIndicator
|
m_EditorClassIdentifier: Assembly-CSharp::TD.Combat.TowerRangeIndicator
|
||||||
rangeProjector: {fileID: 8255517343120954594}
|
rangeProjector: {fileID: 8255517343120954594}
|
||||||
projectionDepth: 50
|
projectionDepth: 50
|
||||||
|
--- !u!114 &5360241685303413177
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 6482414459531823157}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 93bc533262394e1e8b122bbfad89391a, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Assembly-CSharp::TD.Visuals.ConeMesh
|
||||||
|
sides: 16
|
||||||
|
radius: 0.5
|
||||||
|
height: 1
|
||||||
--- !u!1 &7580197837852108944
|
--- !u!1 &7580197837852108944
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
8
Assets/_Project/Scripts/Visuals.meta
Normal file
8
Assets/_Project/Scripts/Visuals.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 16f3da2efd0d4431888e3f04056646c2
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
126
Assets/_Project/Scripts/Visuals/ConeMesh.cs
Normal file
126
Assets/_Project/Scripts/Visuals/ConeMesh.cs
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
// Assets/_Project/Scripts/Visuals/ConeMesh.cs
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace TD.Visuals
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Procedurally generates a cone mesh and assigns it to the GameObject's
|
||||||
|
/// <see cref="MeshFilter"/>. Unity ships no built-in cone primitive, so this
|
||||||
|
/// fills that gap for tower visuals (e.g. the Basic Arrow Tower).
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <b>Visual only.</b> No networking, no collision — the mesh is purely cosmetic.
|
||||||
|
/// The existing MeshRenderer + material (and any owner/paint tinting via
|
||||||
|
/// <c>TowerInstance.tintedRenderers</c>) keep working unchanged.
|
||||||
|
///
|
||||||
|
/// <b>Pivot.</b> The cone is centred on the local origin: its base ring sits at
|
||||||
|
/// <c>y = -height/2</c> and its apex at <c>y = +height/2</c>, matching the vertical
|
||||||
|
/// extents of a unit cube so it sits on a build tile the same way the old cube did.
|
||||||
|
///
|
||||||
|
/// <b>Edit-time.</b> <c>[ExecuteAlways]</c> rebuilds the mesh in the editor so the
|
||||||
|
/// cone is visible without entering play mode. The generated mesh is flagged
|
||||||
|
/// <c>HideFlags.DontSave</c> so it is never written out as a project asset.
|
||||||
|
/// </remarks>
|
||||||
|
[ExecuteAlways]
|
||||||
|
[RequireComponent(typeof(MeshFilter))]
|
||||||
|
public class ConeMesh : MonoBehaviour
|
||||||
|
{
|
||||||
|
[Tooltip("Number of radial segments around the base. Higher = smoother circle.")]
|
||||||
|
[Range(3, 64)]
|
||||||
|
[SerializeField] private int sides = 16;
|
||||||
|
|
||||||
|
[Tooltip("Radius of the cone's base in local units.")]
|
||||||
|
[Min(0.001f)]
|
||||||
|
[SerializeField] private float radius = 0.5f;
|
||||||
|
|
||||||
|
[Tooltip("Height of the cone from base to apex in local units.")]
|
||||||
|
[Min(0.001f)]
|
||||||
|
[SerializeField] private float height = 1f;
|
||||||
|
|
||||||
|
private Mesh mesh;
|
||||||
|
|
||||||
|
private void OnEnable() => Rebuild();
|
||||||
|
|
||||||
|
private void OnValidate()
|
||||||
|
{
|
||||||
|
// OnValidate can fire before OnEnable in the editor; guard the component.
|
||||||
|
if (isActiveAndEnabled) Rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDisable()
|
||||||
|
{
|
||||||
|
// Clean up the generated mesh so it doesn't linger when the object is destroyed.
|
||||||
|
if (mesh != null)
|
||||||
|
{
|
||||||
|
if (Application.isPlaying) Destroy(mesh);
|
||||||
|
else DestroyImmediate(mesh);
|
||||||
|
mesh = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Rebuild()
|
||||||
|
{
|
||||||
|
var filter = GetComponent<MeshFilter>();
|
||||||
|
if (filter == null) return;
|
||||||
|
|
||||||
|
if (mesh == null)
|
||||||
|
{
|
||||||
|
mesh = new Mesh { name = "ProceduralCone", hideFlags = HideFlags.DontSave };
|
||||||
|
}
|
||||||
|
|
||||||
|
BuildCone(mesh);
|
||||||
|
filter.sharedMesh = mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildCone(Mesh target)
|
||||||
|
{
|
||||||
|
target.Clear();
|
||||||
|
|
||||||
|
float halfHeight = height * 0.5f;
|
||||||
|
|
||||||
|
// Vertex layout:
|
||||||
|
// [0 .. sides-1] base ring
|
||||||
|
// [sides] apex
|
||||||
|
// [sides + 1] base centre (for the bottom cap)
|
||||||
|
int baseRingStart = 0;
|
||||||
|
int apexIndex = sides;
|
||||||
|
int baseCentreIndex = sides + 1;
|
||||||
|
|
||||||
|
var vertices = new Vector3[sides + 2];
|
||||||
|
for (int i = 0; i < sides; i++)
|
||||||
|
{
|
||||||
|
float angle = (i / (float)sides) * Mathf.PI * 2f;
|
||||||
|
vertices[baseRingStart + i] = new Vector3(
|
||||||
|
Mathf.Cos(angle) * radius,
|
||||||
|
-halfHeight,
|
||||||
|
Mathf.Sin(angle) * radius);
|
||||||
|
}
|
||||||
|
vertices[apexIndex] = new Vector3(0f, halfHeight, 0f);
|
||||||
|
vertices[baseCentreIndex] = new Vector3(0f, -halfHeight, 0f);
|
||||||
|
|
||||||
|
// Side faces (base ring -> apex) + base cap (fan from centre).
|
||||||
|
// Wind both so they face outward / downward respectively.
|
||||||
|
var triangles = new int[sides * 3 * 2];
|
||||||
|
int t = 0;
|
||||||
|
for (int i = 0; i < sides; i++)
|
||||||
|
{
|
||||||
|
int next = (i + 1) % sides;
|
||||||
|
|
||||||
|
// Side triangle, outward-facing.
|
||||||
|
triangles[t++] = baseRingStart + i;
|
||||||
|
triangles[t++] = apexIndex;
|
||||||
|
triangles[t++] = baseRingStart + next;
|
||||||
|
|
||||||
|
// Base cap triangle, downward-facing.
|
||||||
|
triangles[t++] = baseCentreIndex;
|
||||||
|
triangles[t++] = baseRingStart + next;
|
||||||
|
triangles[t++] = baseRingStart + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
target.vertices = vertices;
|
||||||
|
target.triangles = triangles;
|
||||||
|
target.RecalculateNormals();
|
||||||
|
target.RecalculateBounds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/_Project/Scripts/Visuals/ConeMesh.cs.meta
Normal file
11
Assets/_Project/Scripts/Visuals/ConeMesh.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 93bc533262394e1e8b122bbfad89391a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Loading…
Add table
Add a link
Reference in a new issue