Beispiel #1
0
func distFromPointToSeg(p linear.Vec2, s linear.Seg2) float64 {
	s.P = s.P.Sub(p)
	s.Q = s.Q.Sub(p)
	cross := s.Ray().Cross()
	crossSeg := linear.Seg2{Q: cross}
	if crossSeg.Left(s.P) != crossSeg.Left(s.Q) {
		return s.DistFromOrigin()
	}
	da := s.P.Mag()
	db := s.Q.Mag()
	if da < db {
		return da
	}
	return db
}
Beispiel #2
0
func (e addRiftWalkFireEvent) Apply(_g interface{}) {
	g := _g.(*game.Game)
	player, ok := g.Ents[e.PlayerGid].(*game.PlayerEnt)
	if !ok {
		return
	}
	proc := player.Processes[100+e.ProcessId]
	if proc == nil {
		return
	}
	rwProc, ok := proc.(*riftWalkProcess)
	if !ok {
		return
	}
	if rwProc.Stored.Magnitude() <= rwProc.Threshold {
		return
	}
	dist, radius := rwProc.GetVals()
	rwProc.Stored = game.Mana{}
	movement := (linear.Vec2{dist, 0}).Rotate(player.Angle)
	dest := player.Pos().Add(movement)

	inside := false
	// Check if the player would end up inside a polygon
	for _, poly := range g.Levels[player.Level()].Room.Walls {
		if linear.VecInsideConvexPoly(dest, poly) {
			inside = true
			break
		}
	}

	// If the player would end up inside a polygon then intersect the segment the
	// player would move along with all line segements and move the player to the
	// nearest intersection point.
	if inside {
		moveSeg := linear.Seg2{player.Pos(), dest}
		closest := dest
		var collisionSeg linear.Seg2
		for _, poly := range g.Levels[player.Level()].Room.Walls {
			for i := range poly {
				seg := poly.Seg(i)
				if seg.DoesIsect(moveSeg) {
					isect := seg.Isect(moveSeg)
					if isect.Sub(player.Pos()).Mag2() < closest.Sub(player.Pos()).Mag2() {
						closest = isect
						collisionSeg = seg
					}
				}
			}
		}
		if collisionSeg.Ray().Mag2() == 0 {
			dest = closest.Sub(movement.Norm().Scale(player.Stats().Size() * 2))
		} else {
			nudge := collisionSeg.Ray().Norm().Cross().Scale(player.Stats().Size())
			dest = closest.Add(nudge)
		}
	}

	for _, ent := range g.Ents {
		if ent == player {
			continue
		}
		doDamage := false
		if ent.Pos().Sub(dest).Mag() <= radius+ent.Stats().Size() {
			angle := dest.Sub(ent.Pos()).Angle()
			ent.ApplyForce((linear.Vec2{-rwProc.Force, 0}).Rotate(angle))
			doDamage = true
		} else {
			ray := dest.Sub(player.Pos())
			perp := ray.Cross().Norm()
			scaledPerp := perp.Scale(ent.Stats().Size() + player.Stats().Size())
			sideRay0 := linear.Seg2{player.Pos().Add(scaledPerp), dest.Add(scaledPerp)}
			sideRay1 := linear.Seg2{player.Pos().Sub(scaledPerp), dest.Sub(scaledPerp)}
			if sideRay0.Left(ent.Pos()) != sideRay1.Left(ent.Pos()) {
				// We know the ent lies between sideRays 0 and 1, now we need to make
				// sure it lies between src and dst.
				forward := ent.Pos().Sub(dest)
				backward := ent.Pos().Sub(player.Pos())
				if (forward.Dot(ray) < 0) != (backward.Dot(ray) < 0) {
					if (linear.Seg2{player.Pos(), dest}).Left(ent.Pos()) {
						ent.ApplyForce(perp.Scale(rwProc.Force))
					} else {
						ent.ApplyForce(perp.Scale(-rwProc.Force))
					}
					doDamage = true
				}
			}
		}
		if doDamage {
			ent.Stats().ApplyDamage(stats.Damage{stats.DamageFire, 50})
		}
	}
	player.SetPos(dest)
}