simulation.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Copyright 2016 The G3N Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package physics
  5. import (
  6. "time"
  7. )
  8. type ICollidable interface {
  9. Collided() bool
  10. Static() bool
  11. //GetCollisions() []*Collision
  12. }
  13. type CollisionGroup struct {
  14. // TODO future
  15. }
  16. // Simulation represents a physics simulation.
  17. type Simulation struct {
  18. forceFields []ForceField
  19. bodies []*Body
  20. particles []*Particle
  21. //dynamical []int // non collidable but still affected by force fields
  22. //collidables []ICollidable
  23. }
  24. // NewSimulation creates and returns a pointer to a new physics simulation.
  25. func NewSimulation() *Simulation {
  26. b := new(Simulation)
  27. return b
  28. }
  29. // AddForceField adds a force field to the simulation.
  30. func (s *Simulation) AddForceField(ff ForceField) {
  31. s.forceFields = append(s.forceFields, ff)
  32. }
  33. // RemoveForceField removes the specified force field from the simulation.
  34. // Returns true if found, false otherwise.
  35. func (s *Simulation) RemoveForceField(ff ForceField) bool {
  36. for pos, current := range s.forceFields {
  37. if current == ff {
  38. copy(s.forceFields[pos:], s.forceFields[pos+1:])
  39. s.forceFields[len(s.forceFields)-1] = nil
  40. s.forceFields = s.forceFields[:len(s.forceFields)-1]
  41. return true
  42. }
  43. }
  44. return false
  45. }
  46. // AddBody adds a body to the simulation.
  47. func (s *Simulation) AddBody(rb *Body) {
  48. s.bodies = append(s.bodies, rb)
  49. }
  50. // RemoveBody removes the specified body from the simulation.
  51. // Returns true if found, false otherwise.
  52. func (s *Simulation) RemoveBody(rb *Body) bool {
  53. for pos, current := range s.bodies {
  54. if current == rb {
  55. copy(s.bodies[pos:], s.bodies[pos+1:])
  56. s.bodies[len(s.bodies)-1] = nil
  57. s.bodies = s.bodies[:len(s.bodies)-1]
  58. return true
  59. }
  60. }
  61. return false
  62. }
  63. // AddParticle adds a particle to the simulation.
  64. func (s *Simulation) AddParticle(rb *Particle) {
  65. s.particles = append(s.particles, rb)
  66. }
  67. // RemoveParticle removes the specified particle from the simulation.
  68. // Returns true if found, false otherwise.
  69. func (s *Simulation) RemoveParticle(rb *Particle) bool {
  70. for pos, current := range s.particles {
  71. if current == rb {
  72. copy(s.particles[pos:], s.particles[pos+1:])
  73. s.particles[len(s.particles)-1] = nil
  74. s.particles = s.particles[:len(s.particles)-1]
  75. return true
  76. }
  77. }
  78. return false
  79. }
  80. func (s *Simulation) applyForceFields(frameDelta time.Duration) {
  81. for _, ff := range s.forceFields {
  82. for _, rb := range s.bodies {
  83. pos := rb.GetNode().Position()
  84. force := ff.ForceAt(&pos)
  85. //log.Error("force: %v", force)
  86. //log.Error("mass: %v", rb.mass)
  87. //log.Error("frameDelta: %v", frameDelta.Seconds())
  88. vdiff := force.MultiplyScalar(float32(frameDelta.Seconds())/rb.mass)
  89. //log.Error("vdiff: %v", vdiff)
  90. rb.velocity.Add(vdiff)
  91. }
  92. }
  93. for _, ff := range s.forceFields {
  94. for _, rb := range s.particles {
  95. pos := rb.GetNode().Position()
  96. force := ff.ForceAt(&pos)
  97. //log.Error("force: %v", force)
  98. //log.Error("mass: %v", rb.mass)
  99. //log.Error("frameDelta: %v", frameDelta.Seconds())
  100. vdiff := force.MultiplyScalar(float32(frameDelta.Seconds())/rb.mass)
  101. //log.Error("vdiff: %v", vdiff)
  102. rb.velocity.Add(vdiff)
  103. }
  104. }
  105. }
  106. // updatePositions integrates the velocity of the objects to obtain the position in the next frame.
  107. func (s *Simulation) updatePositions(frameDelta time.Duration) {
  108. for _, rb := range s.bodies {
  109. pos := rb.GetNode().Position()
  110. posDelta := rb.velocity
  111. posDelta.MultiplyScalar(float32(frameDelta.Seconds()))
  112. pos.Add(&posDelta)
  113. rb.GetNode().SetPositionVec(&pos)
  114. }
  115. for _, rb := range s.particles {
  116. pos := rb.GetNode().Position()
  117. posDelta := rb.velocity
  118. posDelta.MultiplyScalar(float32(frameDelta.Seconds()))
  119. pos.Add(&posDelta)
  120. rb.GetNode().SetPositionVec(&pos)
  121. }
  122. }
  123. //func (s *Simulation) CheckCollisions() []*Collision{//collidables []ICollidable) {
  124. //
  125. // return
  126. //}
  127. func (s *Simulation) Backtrack() {
  128. }
  129. // Step steps the simulation.
  130. func (s *Simulation) Step(frameDelta time.Duration) {
  131. // Check for collisions
  132. //collisions := s.CheckCollisions()
  133. //if len(collisions) > 0 {
  134. // // Backtrack to 0 penetration
  135. // s.Backtrack()
  136. //}
  137. // Apply static forces/inertia/impulses (only to objects that did not collide)
  138. s.applyForceFields(frameDelta)
  139. // s.applyDrag(frameDelta) // TODO
  140. // Apply impact forces/inertia/impulses to objects that collided
  141. //s.applyImpactForces(frameDelta)
  142. // Update object positions based on calculated final speeds
  143. s.updatePositions(frameDelta)
  144. }