Skip to content

Instantly share code, notes, and snippets.

@timetocode
Last active February 9, 2017 04:48
Show Gist options
  • Save timetocode/59edb652c4c1362333b4 to your computer and use it in GitHub Desktop.
Save timetocode/59edb652c4c1362333b4 to your computer and use it in GitHub Desktop.
An entity with some of its logic in a physics and collider component, and the rest (weapon, hitpoints) just written directly in SumoShip entity
var nengi = require('../../nengi/nengi')
var Vector2 = nengi.Vector2
function PhysicsComponent(gameObject, config) {
nengi.Component.call(this, gameObject, config)
// force applied from external sources
this.externalForce = new Vector2()
// force applied from own entity (e.g. engine or movement abilities)
this.internalForce = new Vector2()
// velocity of this entity
this.velocity = new Vector2()
this.mass = 1000
this.frictionCoef = 3
}
PhysicsComponent.prototype = Object.create(nengi.Component.prototype)
PhysicsComponent.prototype.constructor = PhysicsComponent
PhysicsComponent.prototype.initialize = function() {
}
PhysicsComponent.prototype.addInternalForce = function(force) {
this.internalForce.add(force)
}
PhysicsComponent.prototype.addExternalForce = function(force) {
//console.log('addExternalForce', force)
this.externalForce.add(force)
}
PhysicsComponent.prototype.update = function(delta, tick, now) {
var externalAcceleration = new Vector2(
this.externalForce.x / this.mass,
this.externalForce.y / this.mass
)
var internalAcceleration = new Vector2(
this.internalForce.x / this.mass,
this.internalForce.y / this.mass
)
// artificial friction to make the controls nice
this.velocity.x += (externalAcceleration.x - this.frictionCoef * this.velocity.x) * delta
this.velocity.y += (externalAcceleration.y - this.frictionCoef * this.velocity.y) * delta
this.velocity.x += (internalAcceleration.x - this.frictionCoef * this.velocity.x) * delta
this.velocity.y += (internalAcceleration.y - this.frictionCoef * this.velocity.y) * delta
this.position.add(this.velocity)
// set forces to 0
this.externalForce.x = 0
this.externalForce.y = 0
this.internalForce.x = 0
this.internalForce.y = 0
}
module.exports = PhysicsComponent
var nengi = require('../../nengi/nengi')
var PhysicsComponent = require('./PhysicsComponent')
var CircleColliderComponent = require('./CircleColliderComponent')
var Projectile = require('./Projectile')
function SumoShip() {
nengi.Entity.call(this)
this.addComponent('physics', new PhysicsComponent(this))
this.addComponent('collider', new CircleColliderComponent(this))
this.collider.tags = ['player']
this.collider.collideWithTags = ['asteroid', 'projectile']
// consider making LifeComponent
this.hp = 100
this.isAlive = true
// consider making WeaponComponent
this.isWeaponCharging = false
this.weaponChargeLevel = 1
this.weaponChargeTimestamp = Date.now()
}
SumoShip.prototype = Object.create(nengi.Entity.prototype)
SumoShip.prototype.constructor = SumoShip
SumoShip.prototype.update = function(delta) {
if (this.isWeaponCharging) {
var elapsed = Date.now() - this.weaponChargeTimestamp
var tier = Math.floor(elapsed/1000) + 1
if (tier > 3) { tier = 3 }
this.weaponChargeLevel = tier
} else {
this.weaponChargeLevel = 1
}
}
SumoShip.prototype.move = function(move) {
if (!this.isAlive) return
if (move.W) {
this.physics.addInternalForce({ x: 0, y: -15000 })
}
if (move.A) {
this.physics.addInternalForce({ x: -15000, y: 0 })
}
if (move.S) {
this.physics.addInternalForce({ x: 0, y: 15000 })
}
if (move.D) {
this.physics.addInternalForce({ x: 15000, y: 0 })
}
}
SumoShip.prototype.chargeWeapon = function(charge) {
if (!this.isAlive) return
// fires a shot instantly, and begins charging a larger shot
var dx = this.x - charge.x
var dy = this.y - charge.y
this.rotation = Math.atan2(dy, dx) + 90 * Math.PI/180
this.isWeaponCharging = true
this.weaponChargeTimestamp = Date.now()
var projectile = new Projectile()
projectile.owner = this
projectile.tier = 1
projectile.launch(
new nengi.Vector2(this.x, this.y),
new nengi.Vector2(charge.x, charge.y),
600
)
var kickback = new nengi.Vector2(dx, dy)
kickback.normalize()
this.physics.addExternalForce({
x: kickback.x * 250000,
y: kickback.y * 250000
})
this.instance.addEntity(projectile)
}
SumoShip.prototype.dischargeWeapon = function(charge) {
if (!this.isAlive) return
// how long have we been charging?
var elapsed = Date.now() - this.weaponChargeTimestamp
var tier = Math.floor(elapsed/1000) + 1
if (tier > 3) { tier = 3 }
// do not discharge unless charge reached tier 2 (at least 1 second of charging)
if (tier < 2) {
this.isWeaponCharging = false
return
}
// a larger shot was released
this.isWeaponCharging = false
//this.weaponChargeLevel = 1
var dx = this.x - charge.x
var dy = this.y - charge.y
this.rotation = Math.atan2(dy, dx) + 90 * Math.PI/180
var projectile = new Projectile()
projectile.owner = this
projectile.tier = tier
projectile.launch(
new nengi.Vector2(this.x, this.y),
new nengi.Vector2(charge.x, charge.y),
600
)
var kickback = new nengi.Vector2(dx, dy)
kickback.normalize()
this.physics.addExternalForce({
x: kickback.x * 250000 * tier,
y: kickback.y * 250000 * tier
})
//console.log('discharged', tier, elapsed)
this.instance.addEntity(projectile)
}
// specify which properties should be networked, and their value types
SumoShip.prototype.netSchema = nengi.createEntitySchema({
'id': nengi.UInt16,
'type': nengi.UInt8,
'x': nengi.Int16,
'y': nengi.Int16,
'isAlive': { binaryType: nengi.Boolean, interp: false },
'rotation': nengi.Rotation,
'weaponChargeLevel': { binaryType: nengi.UInt8, interp: false }
}, {
'x': { delta: true, binaryType: nengi.Int8 },
'y': { delta: true, binaryType: nengi.Int8 }
})
module.exports = SumoShip
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment