在团结的3D无尽的亚军比赛中工作时,我遇到了这个问题。当玩家在z方向跑时,我有一个位于玩家面前的平台(分段/道路)列表。我已经下载了一个名为Dreamteck splines的新资产包。因此每个平台都附有一个样条组件。铺设平台后,玩家将抓住样条曲线并根据样条曲线运行。
让我们说玩家在第一个平台上。当玩家到达第一个平台样条曲线的末尾时,会调用library('ggplot2')
library('reshape2')
library("plyr")
## reproducible example of problem: create dummy data
madeup <- data.frame(Year = rep(2000:2015, each=20), Site=rep(c("a","b","c","d"), each=5, times=16),
var1 = rnorm(n=16*20, mean=20, sd=5), var2= rnorm(n=16*20, mean=50, sd=1))
## create ranges of the data by Year and Site
myRange <- function(dat) {range=max(dat, na.rm=TRUE)-min(dat,na.rm = TRUE)}
vardf <- ddply(madeup, .(Site, Year), summarise, var1=myRange(var1),
var2=myRange(var2))
varmelt <- melt(vardf, id.vars = c("Site","Year"))
varmelt$Site <- as.character(varmelt$Site) # this to preserve the new order when rbind called
varmelt <- by(varmelt, list(varmelt$Year, varmelt$variable), function(x) {x <- x[order(x$value),]
x$order <- 1:nrow(x)
return(x)})
varmelt <- do.call(rbind, varmelt)
## create difference between these values so that each site gets plotted cumulatively on the rose plot
## (otherwise areas close to the centre become uninterpretable)
vartest <- by(varmelt, list(varmelt$Year, varmelt$variable), function(x) {
x$diff <- c(x$value[1], diff(x$value))
return(x)
})
vartest <- do.call(rbind,vartest)
## plot rose plot to display how ranges in variables vary by year and between sites
## for this test example we'll just take one variable, but the idea is to facet by variable
max1 <- max(vartest$value[vartest$variable=='var1'])
yearlength <- length(2000:2015)
ggplot(vartest[vartest$variable=="var1",], aes(x=factor(Year), y=diff)) +
theme_bw() +
geom_hline(yintercept = seq(0,max1, by=1), size=0.3, col="grey60",lty=3) +
geom_vline(xintercept=seq(1,yearlength,1), size=0.3, col='grey30', lty=2) +
geom_bar(stat='identity', width=1, size=0.5, aes(col=Site, fill=Site)) +
scale_x_discrete() +
coord_polar() +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())
事件处理程序,它基本上表示在达到样条曲线的终点时您想要发生的事情。所以我想知道如何在达到目的后获得下一个样条曲线。
P =玩家
如上图所示,这是我想要完成的事情。作为平台如何铺设的简要描述是,一旦玩家进入下一条道路,他刚刚通过的道路就会被禁用,以便下次他可以随机方式重复使用玩家面前的道路。
代码:跟踪管理器脚本。 public Segment [] tilePrefabs; public static Segment newSegment;
OnEndReached()
播放器脚本
public static List<Segment> m_Segments;
public static List<Segment> m_PastSegements;
private int m_SafeSegmentLeft;
private int m_PreSegments = -1;
private float startingSegmentDistance = 4f;
private int startingSafeSegments = 2;
private int amtSegmentsOnScreen = 10;
private float segmentRemovalDistace = -40f;
private float m_TotalWorldDistance;
private float m_CurrentSegmentDistance;
void Update ()
{
while (m_Segments.Count < amtSegmentsOnScreen)
{
SpawnNewSegment();
}
m_TotalWorldDistance += scaledSpeed;
m_CurrentSegmentDistance += scaledSpeed;
if (m_CurrentSegmentDistance > m_Segments[0].worldLength)
{
m_CurrentSegmentDistance -= m_Segments[0].worldLength;
m_PastSegements.Add(m_Segments[0]);
m_Segments.RemoveAt(0);
}
Vector3 currentPos;
Quaternion currentRot;
Transform playerTransform = playerMotor.transform;
m_Segments[0].GetPointAtInWorldUnit(m_CurrentSegmentDistance, out currentPos, out currentRot);
bool needRecenter = currentPos.sqrMagnitude > floatingOriginThreshold;
if (needRecenter)
{
int count = m_Segments.Count;
for (int i = 0; i < count; i++)
{
m_Segments[i].transform.position -= currentPos;
}
count = m_PastSegements.Count;
for (int i = 0; i < count; i++)
{
m_PastSegements[i].transform.position -= currentPos;
}
m_Segments[0].GetPointAtInWorldUnit(m_CurrentSegmentDistance, out currentPos, out currentRot);
}
playerTransform.rotation = currentRot;
playerTransform.position = currentPos;
for (int i = 0; i < m_PastSegements.Count; i++)
{
if ((m_PastSegements[i].transform.position - currentPos).z < segmentRemovalDistace)
{
m_PastSegements[i].Cleanup();
m_PastSegements.RemoveAt(i);
i--;
}
}
}
public void SpawnNewSegment()
{
int useSegment = Random.Range(0, tilePrefabs.Length);
if (useSegment == m_PreSegments)
{
useSegment = (useSegment + 1) % tilePrefabs.Length;
}
Segment segmentToUse = tilePrefabs[useSegment];
newSegment = Instantiate(segmentToUse, Vector3.zero, Quaternion.identity);
Vector3 currentExitPoint;
Quaternion currentExitRotation;
if (m_Segments.Count > 0)
m_Segments[m_Segments.Count - 1].GetPointAt(1.0f, out currentExitPoint, out currentExitRotation);
else
{
currentExitPoint = transform.position;
currentExitRotation = transform.rotation;
}
newSegment.transform.rotation = currentExitRotation;
Vector3 entryPoint;
Quaternion entryRotation;
newSegment.GetPointAt(0.0f, out entryPoint, out entryRotation);
Vector3 pos = currentExitPoint + (newSegment.transform.position - entryPoint);
newSegment.transform.position = pos;
newSegment.manager = this;
newSegment.transform.localScale = new Vector3((Random.value > 0.5f ? -1 : 1), 1, 1);
newSegment.objectRoot.localScale = new Vector3(1.0f / newSegment.transform.localScale.x, 1, 1);
if (m_SafeSegmentLeft <= 0)
SpawnObstacle(newSegment);
else
m_SafeSegmentLeft -= 1;
m_Segments.Add(newSegment);
}
分段脚本:附加到每个道路/平台
//Current tile segment;
private Segment currentSegment;
//Spline Follower
private SplineFollower follower
//For Dreamteck spline -->
private Segment nextSegment;
void Start()
{
playerCollider = GetComponent<CapsuleCollider>();
anim = GetComponent<Animator>();
follower = GetComponent<SplineFollower>();
moveLane = currentLane;
follower.onEndReached += Follower_onEndReached;
}
private void Follower_onEndReached()
{
currentSegment = nextSegment;
follower.computer = currentSegment.spline;
}
void OnTriggerEnter(Collider col)
{
nextSegment = col.GetComponentInParent<Segment>();
}
目前我使用碰撞器,每条道路都有一个盒子对撞机组件。一旦玩家到达平台的末端,它就会获得下一个样条组件。它有效,但有时它无法识别下一个样条曲线,并使用相同的样条曲线,导致玩家运行他一次又一次通过的同一平台。
所以我没有想法。所以来到这里寻找解决方案或建议。帮助将不胜感激。
答案 0 :(得分:1)
在这种情况下,我只是将我可能的段存储在List中,然后当我到达结尾时获取下一个段并将当前的第1段移动到结尾或者在列表中移动它的位置。
那是
public Segment currentSegment;
public List<Segment> segments;
void OnEndReached()
{
//Put the completed segmetn back in the list ... probably at the end or randomized anywhere but at the start
segments.Insert(segments.Count-1, currentSegment);
//Now get the next segment
currentSegment = segments[0];
segments.RemoveAt(0);
}
在此模型中,您有一个简单的列表,表示您的细分将在其中显示的顺序,您始终将当前细分设置为列表中的下一个细分,例如索引0并在完成后将它们放回列表中...将它们放在最后或者如果要随机化顺序将它们插入除索引0之外的任何软件中,例如
segments.Insert(UnityEngine.Random.Range(1, segments.Count), currentSegment);
请注意,我从列表中移除了我所在的细分...列表只代表即将到来的订单,在跑步游戏中我发现它很方便知道,例如所以我可以重置一些东西,根据性能,分数等改变片段的属性。
答案 1 :(得分:0)
如果你正在处理2D碰撞器,使用OnTriggerEnter或OnTriggerEnter2D应该可以胜任。但正如你所说,你已经在使用对手,我认为这就是你所尝试过的。
你可以尝试:
OnTriggerStay
将Raycast渲染到地面物体。在此链接中有一个2D示例:https://kylewbanks.com/blog/unity-2d-checking-if-a-character-or-object-is-on-the-ground-using-raycasts
您还可以使用3D对象进行光线投射。
在这种情况下,您将使用它基本上是拍摄激光&#34;进入你的玩家下方的地面并根据你告诉它击中的图层抓住那里的一个物体。所以,如果你有一个名为&#34; Ground&#34;您的平台所属的平台,然后它只能从该层返回对象。
请记住经常光线投射,以便更新以反映游戏。