Realtime HTML5 Multiplayer Games with Node
Found a video link to my JSConf 2010 (2010!!! Yikes! 10 years ago!)
Found a video link to my JSConf 2010 (2010!!! Yikes! 10 years ago!)
Gravity is by far the best force in the universe. Despite being the weakest of the “main” four (strong nuclear force, weak nuclear force, electromagnetism, gravity). It is the one that dominates given enough time and distances. All this even though it falls of inversely to the square of the distance, meaning, if you double the separation between the two objects you quarter the force, or if you cut the separation in half you quadruple the force of attraction.
It’s also one of my favorite things when creating visualizations, because things move so beautifully when you simply let gravity take over.
So I thought I would give it it’s own tiny blog post, in honor of its value 0.00000000000667
// Compute the net force acting between the invoking body a and b, and
// add to the net force acting on the invoking Body
public void addForce(Body b) {
Body a = this;
double G = 0.00000000000667;
double EPS = 0.0001; // softening parameter
double dx = b.rx - a.rx;
double dy = b.ry - a.ry;
double dist = Math.sqrt(dx*dx + dy*dy);
double F = (G * a.mass * b.mass) / (dist*dist + EPS*EPS);
a.fx += F * dx / dist;
a.fy += F * dy / dist;
}
Simple snippet to load JSON into from a filepath or URL
// Retrieves JSON from bundle
private func loadJSON(fileURL:URL)->[String : Any]? {
// Parse the JSON
do {
// Create a string out of the file contents
let contents = try String(contentsOf: fileURL) // use contentsOfFile for strings
// Turn it into data to feed JSONSerialization class
let data = contents.data(using: String.Encoding.utf8)
// Attempt to turn it into JSON, or show error
let json:[String:Any]? = try? JSONSerialization.jsonObject(with: data!, options: []) as! [String : Any]
return json
} catch {
Swift.print("Error parsing json")
return nil
}
}
There are many ways to do this, however this simple method below has worked for me better than window?.makeKeyAndOrderFront(self)
override func viewDidAppear() {
super.viewDidAppear()
NSApp.activate(ignoringOtherApps: true)
}
If you have a T value, in the range of [0.0-1.0] you can convert that to a local T value for each part of that curve.
var rangePerItem = 1.0 / items.length;
var t = 0.73;
for(var i = 0; i < items.length; i++) {
// determine which piece of the line this item falls into
var a = i * rangePerItem;
var b = (i + 1) * rangePerItem;
// normalize the value so that 0.51 on the third one becomes 1.0 for the first and second, and 0.2 for the third, and 0 for the 4th
var localT = (t - a) / (b - a);
localT = clamp(localT, 0, 1);
item.update(localT);
}
If you’re tired of MonoDevelop’s editing capabilities, you should try VSCode!
It’s super snappy, and lightweight
brew install mono
(need this for intellisense to work)It’s really useful to fire a function when an animation is complete.
There’s no built in way to do that in CoreAnimation, it does have the concept of delegate’s, which get you half way there.
However if you have multiple animations firing, and your delegate is catching everything, you’re gonna be in for a world of hurt.
Here is a simple Swift class I wrote to extend CAAnimation to accept onStart
/onCompletion
blocks:
//
// CAAnimation+BlockCallback.swift
//
import UIKit
//
// Modified from http://onedayitwillmake.com/blog/2016/06/caanimation-completion-callback-block/
// Updated for Swift 4 syntax
// All credit to the original author (Mario Gonzalez)
//
// USAGE:
//
// var animation = CABasicAnimation(keyPath: "strokeEnd")
// animation.duration = duration
// animation.fromValue = 0.0
// animation.toValue = 1.0
// animation.startBlock { startingAnimation, status in
// print("Starting...")
// }
// animation.completionBlock { completingAnimation, status in
// print("Completed!")
// }
public typealias CAAnimationBlockCallback = (CAAnimation, Bool) -> ();
public class CAAnimationBlockCallbackDelegate: NSObject, CAAnimationDelegate {
var onStartCallback: CAAnimationBlockCallback?
var onCompleteCallback: CAAnimationBlockCallback?
public func animationDidStart(_ anim: CAAnimation) {
if let startHandler = onStartCallback {
startHandler(anim, true)
}
}
public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if let completionHandler = onCompleteCallback {
completionHandler(anim, flag);
}
}
}
public extension CAAnimation {
// See if there is already a CAAnimationDelegate handling this animation
// If there is, add onStart to it, if not create one
func startBlock(callback: @escaping CAAnimationBlockCallback) {
if let myDelegate = self.delegate as? CAAnimationBlockCallbackDelegate {
myDelegate.onStartCallback = callback;
} else {
let callbackDelegate = CAAnimationBlockCallbackDelegate()
callbackDelegate.onStartCallback = callback
self.delegate = callbackDelegate
}
}
// See if there is already a CAAnimationDelegate handling this animation
// If there is, add onCompletion to it, if not create one
func completionBlock(callback: @escaping CAAnimationBlockCallback) {
if let myDelegate = self.delegate as? CAAnimationBlockCallbackDelegate {
myDelegate.onCompleteCallback = callback
} else {
let callbackDelegate = CAAnimationBlockCallbackDelegate()
callbackDelegate.onCompleteCallback = callback
self.delegate = callbackDelegate
}
}
}
CAAnimation
provides a way of receiving a callback upon start or completion of an animation.
If you have a ‘pure’ class, that is a class that does not inherit from anything, doing this will have no effect:
class Petal {
func startAnimation(duration: Double = 2.0) {
let pathAnimation = CABasicAnimation(keyPath: "strokeEnd");
pathAnimation!.delegate = self;
pathAnimation!.duration = duration;
pathAnimation!.fromValue = 0.0;
pathAnimation!.toValue = 1.0;
self.shapeLayer.addAnimation(pathAnimation!, forKey: "strokeEnd");
}
func animationDidStart(anim: CAAnimation) {
Swift.print("ANIMATION DID START!");
}
func animationDidStop(anim: CAAnimation, finished flag: Bool) {
Swift.print("ANIMATION DID END!");
}
}
The reason is because:
You must subclass NSObject, as the delegate methods exist as an informal protocol extension on NSObject
So simply changing it to this is enough:
class Petal:NSObject { // Subclass NSObject
func startAnimation(duration: Double = 2.0) {
....
}
// These are now overrides
override func animationDidStart(anim: CAAnimation) {
Swift.print("ANIMATION DID START!");
}
override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
Swift.print("ANIMATION DID END!");
}
}
Sometimes when developing in Swift if you’re trying to do seemingly simple things like divide 2 numbers:
let interval:Double = 1.0/fps;
You’ll get errors like these:
binary operator '*' cannot be applied to operands of type 'CGFloat' and 'Double'
binary operator '*' cannot be applied to operands of type 'Int' and 'CGFloat'
cannot convert value of type 'Float' to expected argument type 'Double'
binary operator '*' cannot be applied to operands of type 'CGFloat' and 'Int8'
This is because Swift is more strict about how it treats numeric types, and you have to manually cast them to the same type in order for those operations to work.
However cause we can write our own operator in Swift, we can make it so that when it encounters 2 types, it will check to see if we have a matching operator and use that instead.
So as I’ve encountered them, I’ve been appending to a my little NumericOperatorOverloadingExtensions.swift
file:
import Foundation
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////// ADDITION ////////////////////////////////////////////////////////////////
public func +(a: Float, scalar: Int) -> Float { return a + Float(scalar); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////// MULTIPLICATION //////////////////////////////////////////////////////////////
// Int *
public func *(a: Int, scalar: CGFloat) -> CGFloat { return CGFloat(a) * scalar; }
public func *(a: Int, scalar: Float) -> Float { return Float(a) * scalar; }
public func *(a: Int, scalar: Double) -> Double { return Double(a) * scalar; }
public func *(scalar: CGFloat, a: Int) -> CGFloat { return CGFloat(a) * scalar; }
public func *(scalar: Float, a: Int) -> Float { return Float(a) * scalar; }
public func *(scalar: Double, a: Int) -> Double { return Double(a) * scalar; }
// Int8 *
public func *(a: Int8, scalar: CGFloat) -> CGFloat { return CGFloat(a) * scalar; }
public func *(a: Int8, scalar: Float) -> Float { return Float(a) * scalar; }
public func *(a: Int8, scalar: Double) -> Double { return Double(a) * scalar; }
public func *(scalar: CGFloat, a: Int8) -> CGFloat { return CGFloat(a) * scalar; }
public func *(scalar: Float, a: Int8) -> Float { return Float(a) * scalar; }
public func *(scalar: Double, a: Int8) -> Double { return Double(a) * scalar; }
// Int32 *
public func *(a: Int32, scalar: CGFloat) -> CGFloat { return CGFloat(a) * scalar; }
public func *(a: Int32, scalar: Float) -> Float { return Float(a) * scalar; }
public func *(a: Int32, scalar: Double) -> Double { return Double(a) * scalar; }
public func *(scalar: CGFloat, a: Int32) -> CGFloat { return CGFloat(a) * scalar; }
public func *(scalar: Float, a: Int32) -> Float { return Float(a) * scalar; }
public func *(scalar: Double, a: Int32) -> Double { return Double(a) * scalar; }
// Float *
public func *(a: Float, scalar: Double) -> Float { return a * Float(scalar); }
public func *(a: Float, scalar: Double) -> CGFloat { return CGFloat(a * Float(scalar)); }
public func *(a: Float, scalar: Double) -> Double { return Double(a) * scalar; }
// CGFLOAT *
public func *(a: CGFloat, scalar: Double) -> CGFloat { return a * CGFloat(scalar); }
public func *(a: CGFloat, scalar: Double) -> Float { return Float(a) * Float(scalar); }
public func *(a: CGFloat, scalar: Double) -> Double { return Double(a) * scalar; }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////// DIVISION ////////////////////////////////////////////////////////////////
// Double /
public func /(a: Double, b: Int) -> Double { return a / Double(b); }
public func /(a: Double, b: Float) -> Double { return a / Double(b); }
public func /(a: Double, b: Int) -> Int { return Int(a) / b; }
public func /(a: Int, b: Double) -> Double { return Double(a) / b; }
public func /(a: Int, b: Double) -> Int { return Int(Double(a) / b); }
// Float /
public func /(a: Float, b: Int) -> Float { return a / Float(b); }
public func /(a: Float, b: Int) -> Int { return Int(a) / b; }
public func /(a: Int, b: Float) -> Float { return Float(a) / b; }
public func /(a: Int, b: Float) -> Int { return Int(Float(a) / b); }
public func /(a: Float, scalar: Double) -> Float { return a / Float(scalar); }
Something you need a specific branch of a repository that has not been published yet.
git+http://git@SUBDOMAIN.DOMAIN.COM/USER/REPO-URL.git#4d331600
For example:
// this URL
https://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs/tree/39333c6227ea537e3f5d4ec9e893d7f9c670c867
// becomes in your package.json
git+https://git@github.com/USERNAME/REPO_NAME.git#39333c6227ea537e3f5d4ec9e893d7f9c670c867
// If that doesn't work, try:
npm install --save git+ssh://git@github.com/USERNAME/REPO_NAME.git#HASH
Swap HTTP for HTTPS, depending on your repo location