예제 #1
0
파일: cubedrop.go 프로젝트: tbogdala/cubez
func fire() {
	const cubesToMake = 4
	var offset float32 = 0.0
	if len(cubes) > 0 && (len(cubes)/cubesToMake)%2 >= 1 {
		offset = 0.75
	}

	for i := 0; i < cubesToMake; i++ {
		e := new(Entity)
		e.Node = CreateCube(-0.5, -0.5, -0.5, 0.5, 0.5, 0.5)
		e.Node.Shader = diffuseShader
		e.Node.Color = mgl.Vec4{1.0, 1.0, 1.0, 1.0}
		e.Node.Location = mgl.Vec3{float32(i*2.0-cubesToMake/2) - 0.5 + offset, 10.0, 0.0}
		e.Node.Tex0 = crateTexture

		// create the collision box for the the cube
		cubeCollider := cubez.NewCollisionCube(nil, m.Vector3{0.5, 0.5, 0.5})
		cubeCollider.Body.Position = m.Vector3{m.Real(i*2.0-cubesToMake/2) - 0.5 + m.Real(offset), 10.0, 0.0}
		cubeCollider.Body.SetMass(8.0)
		cubeCollider.Body.CanSleep = true

		var cubeInertia m.Matrix3
		cubeInertia.SetBlockInertiaTensor(&cubeCollider.HalfSize, 8.0)
		cubeCollider.Body.SetInertiaTensor(&cubeInertia)

		cubeCollider.Body.CalculateDerivedData()
		cubeCollider.CalculateDerivedData()
		e.Collider = cubeCollider

		cubes = append(cubes, e)
	}
}
예제 #2
0
파일: input.go 프로젝트: tbogdala/free
// fireCharMovePosX is the event that moves the character 'right' in standard view.
func fireCharMovePosX(delta float32) {
	movement := locPerSec * delta
	// FIXME: for now we add the force directly. in future, move this to game manager
	// and have it notify server of update.
	playerEnt := gameManager.GetLocalPlayer()
	body := playerEnt.Collider.GetBody()
	body.AddVelocity(&physmath.Vector3{physmath.Real(movement), physmath.Real(-movement * 0.15), 0.0})
}
예제 #3
0
파일: landscape.go 프로젝트: tbogdala/free
func buildCollider(cb *collisionBlock) physics.Collider {
	length := physmath.Real(cb.EndZ - cb.StartZ + 1)
	halfLength := physmath.Real(length) / 2.0

	// create the collision box for the the cube
	cubeCollider := physics.NewCollisionCube(nil, physmath.Vector3{0.5, 0.5, halfLength})
	cubeCollider.Body.Position = physmath.Vector3{physmath.Real(cb.X) + 0.5, physmath.Real(cb.Y) + 0.5, physmath.Real(cb.StartZ) + halfLength}
	cubeCollider.Body.SetInfiniteMass()
	cubeCollider.Body.CanSleep = false
	cubeCollider.Body.CalculateDerivedData()
	cubeCollider.CalculateDerivedData()

	return cubeCollider
}
예제 #4
0
파일: ballistic.go 프로젝트: tbogdala/cubez
func updateCallback(delta float64) {
	updateObjects(delta)
	foundContacts, contacts := generateContacts(delta)
	if foundContacts {
		cubez.ResolveContacts(len(contacts)*8, contacts, m.Real(delta))
	}
}
예제 #5
0
파일: rigidbody.go 프로젝트: tbogdala/cubez
// Integrate takes all of the forces accumulated in the RigidBody and
// change the Position and Orientation of the object.
func (body *RigidBody) Integrate(duration m.Real) {
	if body.IsAwake == false {
		return
	}

	// calculate linear acceleration from force inputs.
	body.lastFrameAccelleration = body.Acceleration
	body.lastFrameAccelleration.AddScaled(&body.forceAccum, body.inverseMass)

	// calculate angular acceleration from torque inputs
	angularAcceleration := body.inverseInertiaTensorWorld.MulVector3(&body.torqueAccum)

	// adjust velocities
	// update linear velocity from both acceleration and impulse
	body.Velocity.AddScaled(&body.lastFrameAccelleration, duration)

	// update angular velocity from both acceleration and impulse
	body.Rotation.AddScaled(&angularAcceleration, duration)

	// impose drag
	body.Velocity.MulWith(m.Real(math.Pow(float64(body.LinearDamping), float64(duration))))
	body.Rotation.MulWith(m.Real(math.Pow(float64(body.AngularDamping), float64(duration))))

	// adjust positions
	// update linear positions
	body.Position.AddScaled(&body.Velocity, duration)

	//update angular position
	body.Orientation.AddScaledVector(&body.Rotation, duration)

	// normalize the orientation and update the matrixes with the new position and orientation
	body.CalculateDerivedData()
	body.ClearAccumulators()

	// update the kinetic energy store and possibly put the body to sleep
	if body.CanSleep {
		currentMotion := body.Velocity.Dot(&body.Velocity) + body.Rotation.Dot(&body.Rotation)
		bias := m.Real(math.Pow(0.5, float64(duration)))
		body.motion = bias*body.motion + (1.0-bias)*currentMotion

		if body.motion < sleepEpsilon {
			body.SetAwake(false)
		} else if body.motion > 10*sleepEpsilon {
			body.motion = 10 * sleepEpsilon
		}
	}
}
예제 #6
0
파일: ballistic.go 프로젝트: tbogdala/cubez
// update object locations
func updateObjects(delta float64) {
	// for now there's only one box to update
	body := cube.Collider.GetBody()
	body.Integrate(m.Real(delta))
	cube.Collider.CalculateDerivedData()

	// for now we hack in the position and rotation of the collider into the renderable
	SetGlVector3(&cube.Node.Location, &body.Position)
	SetGlQuat(&cube.Node.LocalRotation, &body.Orientation)

	for _, bullet := range bullets {
		bulletBody := bullet.Collider.GetBody()
		bulletBody.Integrate(m.Real(delta))
		bullet.Collider.CalculateDerivedData()
		SetGlVector3(&bullet.Node.Location, &bulletBody.Position)
		SetGlQuat(&bullet.Node.LocalRotation, &bulletBody.Orientation)
	}
}
예제 #7
0
파일: cubedrop.go 프로젝트: tbogdala/cubez
// update object locations
func updateObjects(delta float64) {
	for _, cube := range cubes {
		body := cube.Collider.GetBody()
		body.Integrate(m.Real(delta))
		cube.Collider.CalculateDerivedData()

		// for now we hack in the position and rotation of the collider into the renderable
		SetGlVector3(&cube.Node.Location, &body.Position)
		SetGlQuat(&cube.Node.LocalRotation, &body.Orientation)
	}
}
예제 #8
0
파일: contact.go 프로젝트: tbogdala/cubez
// Constructs an arbitrary orthonormal basis for the contact. It's stored
// as a 3x3 matrix where each column is a vector for an axis. The x axis
// is based off of the contact normal and the y and z axis will be generated
// so that they are at right angles to it.
func (c *Contact) calculateContactBasis() {
	var contactTangentY m.Vector3
	var contactTangentZ m.Vector3

	absContactNormalX := m.RealAbs(c.ContactNormal[0])
	absContactNormalY := m.RealAbs(c.ContactNormal[1])

	// check whether the z axis is nearer to the x or y axis
	if absContactNormalX > absContactNormalY {
		// generate a scaling factor to ensure results are normalized
		s := m.Real(1.0) / m.RealSqrt(c.ContactNormal[2]*c.ContactNormal[2]+c.ContactNormal[0]*c.ContactNormal[0])

		// the new x axis is at right angles to the world y axis
		contactTangentY[0] = c.ContactNormal[2] * s
		contactTangentY[1] = 0
		contactTangentY[2] = c.ContactNormal[0] * -s

		// the new y axis is at right angles to the new x and z axes
		contactTangentZ[0] = c.ContactNormal[1] * contactTangentY[0]
		contactTangentZ[1] = c.ContactNormal[2]*contactTangentY[0] - c.ContactNormal[0]*contactTangentY[2]
		contactTangentZ[2] = -c.ContactNormal[1] * contactTangentY[0]
	} else {
		// generate a scaling factor to ensure results are normalized
		s := m.Real(1.0) / m.RealSqrt(c.ContactNormal[2]*c.ContactNormal[2]+c.ContactNormal[1]*c.ContactNormal[1])

		// the new x axis is at right angles to the world y axis
		contactTangentY[0] = 0
		contactTangentY[1] = -c.ContactNormal[2] * s
		contactTangentY[2] = c.ContactNormal[1] * s

		// the new y axis is at right angles to the new x and z axes
		contactTangentZ[0] = c.ContactNormal[1]*contactTangentY[2] - c.ContactNormal[2]*contactTangentY[1]
		contactTangentZ[1] = -c.ContactNormal[0] * contactTangentY[2]
		contactTangentZ[2] = c.ContactNormal[0] * contactTangentY[1]
	}

	// now set the contactToWorld matrix based off of these three vectors
	c.contactToWorld.SetComponents(&c.ContactNormal, &contactTangentY, &contactTangentZ)
}
예제 #9
0
파일: entity.go 프로젝트: tbogdala/free
// SyncToColliders syncs the location and orientation to the collision object
// and the bounding box.
func (e *Entity) SyncToColliders() {
	if e.Collider == nil {
		return
	}

	body := e.Collider.GetBody()
	body.Position[0] = physmath.Real(e.Location[0])
	body.Position[1] = physmath.Real(e.Location[1])
	body.Position[2] = physmath.Real(e.Location[2])
	body.Orientation[0] = physmath.Real(e.Rotation.W)
	body.Orientation[1] = physmath.Real(e.Rotation.V[0])
	body.Orientation[2] = physmath.Real(e.Rotation.V[1])
	body.Orientation[3] = physmath.Real(e.Rotation.V[2])
	e.BoundingBox.Offset[0] = e.Location[0]
	e.BoundingBox.Offset[1] = e.Location[1]
	e.BoundingBox.Offset[2] = e.Location[2]
}
예제 #10
0
파일: entity.go 프로젝트: tbogdala/free
// RunCollider updates the physics collider for the entity if it's present
func (e *Entity) RunCollider(delta float32) {
	// if there's no collider just return
	if e.Collider == nil {
		return
	}

	// for now there's only one box to update
	body := e.Collider.GetBody()

	// we don't process entities with infinite mass
	if body.HasFiniteMass() == false {
		return
	}

	body.Integrate(physmath.Real(delta))
	e.Collider.CalculateDerivedData()

	// pull the positions from the collider into the entity
	e.SyncFromCollider()

	// and then push them to the renderable
	e.SyncToRenderable()
}
예제 #11
0
// UpdatePhysics makes sure the physics objects are updated.
func (gm *LocalGameManager) UpdatePhysics(frameDelta float32) {
	if gm.physicsEnabled == false {
		return
	}

	physicsNow := time.Now()
	physicsDelta := float32(physicsNow.Sub(gm.physicsLastTime).Seconds())

	// sync physics to no more than 60 fps
	if physicsDelta < 1.0/60.0 {
		return
	}

	// conversely, if it's been too long, we just act like nothing happened ...
	// what's up with that?
	if physicsDelta > 0.50 {
		// try again next time to see if we can process the world
		gm.physicsLastTime = physicsNow
		groggy.Logsf("INFO", "LGM:UpdatePhycis() had to skip a physics frame due to excessive lag in delta time (%f)", physicsDelta)
		return
	}

	// update the collider in each entity
	gm.entityManager.Map(func(e *entity.Entity) {
		if e.Collider != nil {
			e.RunCollider(physicsDelta)
		}
	})

	// generate any contacts
	//groggy.Logsf("DEBUG", "LGM: UpdatePhysics: checking start")
	var contacts []*physics.Contact
	gm.entityManager.Map(func(e *entity.Entity) {
		if e.Collider != nil {
			// test collisions against other entities
			// TODO: do better coarse collision detection
			gm.entityManager.Map(func(otherEnt *entity.Entity) {
				if e != otherEnt && otherEnt.Collider != nil {
					//groggy.Logsf("DEBUG", "\tLGM: UpdatePhysics: checking entitys:")
					//groggy.Logsf("DEBUG", "\t\tentity %d(%s) @ (%v)", e.Id, e.Name, e.Collider.GetTransform())
					//groggy.Logsf("DEBUG", "\t\t%v", e.Collider.GetBody())
					//groggy.Logsf("DEBUG", "\t\tentity %d(%s) @ (%v)", otherEnt.Id, otherEnt.Name, otherEnt.Collider.GetTransform())
					//groggy.Logsf("DEBUG", "\t\t%v", otherEnt.Collider.GetBody())
					_, contacts = physics.CheckForCollisions(e.Collider, otherEnt.Collider, contacts)
				}
			})

			// stop here with the infinite mass, non-movable entities
			if e.Collider.GetBody().HasFiniteMass() == false {
				return
			}

			// Now check the entity against the landscape chunks
			// TODO: super lame selections of chunks and very wasteful
			intX, intZ := int(e.Location[0]), int(e.Location[2])
			chunks := gm.landscapeMan.GetChunksFor(intX, intZ)
			chunks = append(chunks, gm.landscapeMan.GetChunksFor(intX, intZ+1)...)
			chunks = append(chunks, gm.landscapeMan.GetChunksFor(intX, intZ-1)...)
			chunks = append(chunks, gm.landscapeMan.GetChunksFor(intX+1, intZ-1)...)
			chunks = append(chunks, gm.landscapeMan.GetChunksFor(intX-1, intZ-1)...)
			for _, chunk := range chunks {
				// check collision against the relevant landscape collisions
				for _, chunkCollider := range chunk.Colliders {
					_, contacts = physics.CheckForCollisions(e.Collider, chunkCollider, contacts)
				}
			}
		}
	})

	// resolve the contacts
	if contacts != nil && len(contacts) > 0 {
		physics.ResolveContacts(len(contacts)*2, contacts, physmath.Real(physicsDelta))
	}

	gm.physicsLastTime = physicsNow
}