Skip to content

Commit

Permalink
Merge pull request #260 from ubclaunchpad/seerat/junk-hole-concurrency
Browse files Browse the repository at this point in the history
Make junk and hole class concurrency-proof
  • Loading branch information
brian-nguyen committed Nov 4, 2018
2 parents 90f4846 + 33b4aca commit 68e2d9b
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 58 deletions.
10 changes: 0 additions & 10 deletions client/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import React from 'react';
import GameOverModal from './components/GameOverModal';
import WelcomeModal from './components/WelcomeModal';
import { drawGame, drawWalls } from './components/GameObjects';
import Minimap from './components/Minimap';
import Leaderboard from './components/Leaderboard';

import {
Expand Down Expand Up @@ -217,15 +216,6 @@ export default class App extends React.Component {
<div style={styles.canvasContainer}>
<Leaderboard players={this.state.players} />
<canvas id="ctx" style={styles.canvas} display="inline" width={window.innerWidth - 20} height={window.innerHeight - 20} margin={0} />
{
this.state.showMiniMap &&
<Minimap
arena={this.state.arena}
junk={this.state.junk}
players={this.state.players}
holes={this.state.holes}
/>
}
{
this.state.showWelcomeModal &&
<WelcomeModal
Expand Down
2 changes: 1 addition & 1 deletion client/components/GameObjects.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export function drawGame(data, canvas) {
});

const holes = data.holes.map((h) => {
if (!h.position) {
if (!h || !h.position) {
return {
position: { x: 0, y: 0 },
radius: 0,
Expand Down
85 changes: 78 additions & 7 deletions server/models/hole.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package models
import (
"math"
"math/rand"
"sync"
)

// Hole related constants
Expand All @@ -24,6 +25,7 @@ type Hole struct {
IsAlive bool `json:"isAlive"`
Life float64 `json:"-"`
StartingLife float64 `json:"-"`
rwMutex sync.RWMutex
}

// CreateHole initializes and returns an instance of a Hole
Expand All @@ -37,24 +39,93 @@ func CreateHole(position Position) *Hole {
Life: life,
IsAlive: false,
StartingLife: life,
rwMutex: sync.RWMutex{},
}
return &h
}

// Getters
func (h *Hole) getPosition() Position {
h.rwMutex.RLock()
defer h.rwMutex.RUnlock()

return h.Position
}

func (h *Hole) getLife() float64 {
h.rwMutex.RLock()
defer h.rwMutex.RUnlock()

return h.Life
}

func (h *Hole) getRadius() float64 {
h.rwMutex.RLock()
defer h.rwMutex.RUnlock()

return h.Radius
}

func (h *Hole) getGravityRadius() float64 {
h.rwMutex.RLock()
defer h.rwMutex.RUnlock()

return h.GravityRadius
}

func (h *Hole) getStartingLife() float64 {
h.rwMutex.RLock()
defer h.rwMutex.RUnlock()

return h.StartingLife
}

// Setters

func (h *Hole) setIsAlive(isAlive bool) {
h.rwMutex.Lock()
defer h.rwMutex.Unlock()

h.IsAlive = isAlive
}

func (h *Hole) setLife(life float64) {
h.rwMutex.Lock()
defer h.rwMutex.Unlock()

h.Life = life
}

func (h *Hole) setRadius(radius float64) {
h.rwMutex.Lock()
defer h.rwMutex.Unlock()

h.Radius = radius
}

func (h *Hole) setGravityRadius(gravityRadius float64) {
h.rwMutex.Lock()
defer h.rwMutex.Unlock()

h.GravityRadius = gravityRadius
}

// Update reduces this holes life and increases radius if max not reached
func (h *Hole) Update() {
h.Life--
hLife := h.getLife()
hLife--
h.setLife(hLife)

if h.Life < h.StartingLife-HoleInfancy {
h.IsAlive = true
if hLife < h.getStartingLife()-HoleInfancy {
h.setIsAlive(true)
}
if h.Radius < MaxHoleRadius*1.2 {
h.Radius += 0.02
h.GravityRadius += 0.03
if hRadius := h.getRadius(); hRadius < MaxHoleRadius*1.2 {
h.setRadius(hRadius + 0.02)
h.setGravityRadius(h.getGravityRadius() + 0.03)
}
}

// IsDead checks the lifespan of the hole
func (h *Hole) IsDead() bool {
return h.Life < 0
return h.getLife() < 0
}
163 changes: 127 additions & 36 deletions server/models/junk.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package models

import (
"math"
"sync"
)

// Junk related constants
Expand All @@ -23,6 +24,7 @@ type Junk struct {
LastPlayerHit *Player `json:"-"`
Debounce int `json:"-"`
jDebounce int
rwMutex sync.RWMutex
}

// CreateJunk initializes and returns an instance of a Junk
Expand All @@ -33,95 +35,184 @@ func CreateJunk(position Position) *Junk {
Color: "white",
Debounce: 0,
jDebounce: 0,
rwMutex: sync.RWMutex{},
}
}

// Getters

func (j *Junk) getPosition() Position {
j.rwMutex.RLock()
defer j.rwMutex.RUnlock()

return j.Position
}

func (j *Junk) getVelocity() Velocity {
j.rwMutex.RLock()
defer j.rwMutex.RUnlock()

return j.Velocity
}

func (j *Junk) getDebounce() int {
j.rwMutex.RLock()
defer j.rwMutex.RUnlock()

return j.Debounce
}

func (j *Junk) getJDebounce() int {
j.rwMutex.RLock()
defer j.rwMutex.RUnlock()

return j.jDebounce
}

// Setters

func (j *Junk) setPosition(pos Position) {
j.rwMutex.Lock()
defer j.rwMutex.Unlock()

j.Position = pos
}

func (j *Junk) setVelocity(v Velocity) {
j.rwMutex.Lock()
defer j.rwMutex.Unlock()

j.Velocity = v
}

func (j *Junk) setDebounce(debounce int) {
j.rwMutex.Lock()
defer j.rwMutex.Unlock()

j.Debounce = debounce
}

func (j *Junk) setJDebounce(jDebounce int) {
j.rwMutex.Lock()
defer j.rwMutex.Unlock()

j.jDebounce = jDebounce
}

func (j *Junk) setColor(color string) {
j.rwMutex.Lock()
defer j.rwMutex.Unlock()

j.Color = color
}

func (j *Junk) setLastPlayerHit(player *Player) {
j.rwMutex.Lock()
defer j.rwMutex.Unlock()

j.LastPlayerHit = player
}

// UpdatePosition Update Junk's position based on calculations of position/velocity
func (j *Junk) UpdatePosition(height float64, width float64) {
if j.Position.X+j.Velocity.Dx > width-JunkRadius || j.Position.X+j.Velocity.Dx < JunkRadius {
j.Velocity.Dx = -j.Velocity.Dx
positionVector := j.getPosition()
velocityVector := j.getVelocity()
if positionVector.X+velocityVector.Dx > width-JunkRadius || positionVector.X+velocityVector.Dx < JunkRadius {
velocityVector.Dx = -velocityVector.Dx
}
if j.Position.Y+j.Velocity.Dy > height-JunkRadius || j.Position.Y+j.Velocity.Dy < JunkRadius {
j.Velocity.Dy = -j.Velocity.Dy
if positionVector.Y+velocityVector.Dy > height-JunkRadius || positionVector.Y+velocityVector.Dy < JunkRadius {
velocityVector.Dy = -velocityVector.Dy
}

j.Velocity.Dx *= JunkFriction
j.Velocity.Dy *= JunkFriction
velocityVector.Dx *= JunkFriction
velocityVector.Dy *= JunkFriction

j.Position.X += j.Velocity.Dx
j.Position.Y += j.Velocity.Dy
positionVector.X += velocityVector.Dx
positionVector.Y += velocityVector.Dy

if j.Debounce > 0 {
j.Debounce--
j.setPosition(positionVector)
j.setVelocity(velocityVector)

if jDebounce := j.getDebounce(); jDebounce > 0 {
j.setDebounce(jDebounce - 1)
} else {
j.Debounce = 0
j.setDebounce(0)
}

if j.jDebounce > 0 {
j.jDebounce--
if jjDebounce := j.getJDebounce(); jjDebounce > 0 {
j.setJDebounce(jjDebounce - 1)
} else {
j.jDebounce = 0
j.setJDebounce(0)
}
}

// HitBy Update Junks's velocity based on calculations of being hit by a player
func (j *Junk) HitBy(p *Player) {
pVelocity := p.getVelocity()
jVelocity := j.getVelocity()
// We don't want this collision till the debounce is down.
if j.Debounce != 0 {
if j.getDebounce() != 0 {
return
}

j.Color = p.getColor() //Assign junk to last recently hit player color
j.LastPlayerHit = p
j.setColor(p.getColor()) //Assign junk to last recently hit player color
j.setLastPlayerHit(p)

if pVelocity.Dx < 0 {
j.Velocity.Dx = math.Min(pVelocity.Dx*BumpFactor, -MinimumBump)
jVelocity.Dx = math.Min(pVelocity.Dx*BumpFactor, -MinimumBump)
} else {
j.Velocity.Dx = math.Max(pVelocity.Dx*BumpFactor, MinimumBump)
jVelocity.Dx = math.Max(pVelocity.Dx*BumpFactor, MinimumBump)
}

if pVelocity.Dy < 0 {
j.Velocity.Dy = math.Min(pVelocity.Dy*BumpFactor, -MinimumBump)
jVelocity.Dy = math.Min(pVelocity.Dy*BumpFactor, -MinimumBump)
} else {
j.Velocity.Dy = math.Max(pVelocity.Dy*BumpFactor, MinimumBump)
jVelocity.Dy = math.Max(pVelocity.Dy*BumpFactor, MinimumBump)
}

j.setVelocity(jVelocity)
p.hitJunk()
j.Debounce = JunkDebounceTicks
j.setDebounce(JunkDebounceTicks)
}

// HitJunk Update Junks's velocity based on calculations of being hit by another Junk
func (j *Junk) HitJunk(jh *Junk) {
// We don't want this collision till the debounce is down.
if j.jDebounce != 0 {
if j.getJDebounce() != 0 {
return
}

initalVelocity := j.Velocity

jInitialVelocity := j.getVelocity()
jVelocity := jInitialVelocity
jhVelocity := jh.getVelocity()
//Calculate this junks's new velocity
j.Velocity.Dx = (j.Velocity.Dx * -JunkVTransferFactor) + (jh.Velocity.Dx * JunkVTransferFactor)
j.Velocity.Dy = (j.Velocity.Dy * -JunkVTransferFactor) + (jh.Velocity.Dy * JunkVTransferFactor)
jVelocity.Dx = (jVelocity.Dx * -JunkVTransferFactor) + (jhVelocity.Dx * JunkVTransferFactor)
jVelocity.Dy = (jVelocity.Dy * -JunkVTransferFactor) + (jhVelocity.Dy * JunkVTransferFactor)

//Calculate other junk's new velocity
jh.Velocity.Dx = (jh.Velocity.Dx * -JunkVTransferFactor) + (initalVelocity.Dx * JunkVTransferFactor)
jh.Velocity.Dy = (jh.Velocity.Dy * -JunkVTransferFactor) + (initalVelocity.Dy * JunkVTransferFactor)
jhVelocity.Dx = (jhVelocity.Dx * -JunkVTransferFactor) + (jInitialVelocity.Dx * JunkVTransferFactor)
jhVelocity.Dy = (jhVelocity.Dy * -JunkVTransferFactor) + (jInitialVelocity.Dy * JunkVTransferFactor)

j.jDebounce = JunkDebounceTicks
jh.jDebounce = JunkDebounceTicks
j.setVelocity(jVelocity)
jh.setVelocity(jhVelocity)
j.setJDebounce(JunkDebounceTicks)
jh.setJDebounce(JunkDebounceTicks)
}

// ApplyGravity applys a vector towards given position
func (j *Junk) ApplyGravity(h *Hole) {
gravityVector := Velocity{0, 0}
gravityVector.Dx = h.Position.X - j.Position.X
gravityVector.Dy = h.Position.Y - j.Position.Y
jVelocity := j.getVelocity()
jPosition := j.getPosition()
hPosition := h.getPosition()

gravityVector := Velocity{0, 0}
gravityVector.Dx = hPosition.X - jPosition.X
gravityVector.Dy = hPosition.Y - jPosition.Y
inverseMagnitude := 1.0 / gravityVector.magnitude()
gravityVector.normalize()

//Velocity is affected by how close you are, the size of the hole, and a damping factor.
j.Velocity.Dx += gravityVector.Dx * inverseMagnitude * h.Radius * JunkGravityDamping
j.Velocity.Dy += gravityVector.Dy * inverseMagnitude * h.Radius * JunkGravityDamping
jVelocity.Dx += gravityVector.Dx * inverseMagnitude * h.getRadius() * JunkGravityDamping
jVelocity.Dy += gravityVector.Dy * inverseMagnitude * h.getRadius() * JunkGravityDamping
j.setVelocity(jVelocity)
}
Loading

0 comments on commit 68e2d9b

Please sign in to comment.