ecs = require("ecs") shim = require("shader_shim") win = require("window") sprites = require("world.sprites") world = require("world") aspect = win.width / win.height player_tiny = 6 s_mv = mat4( 1, 0, 0, 0, 0, aspect, 0, 0, 0, 0, 1, 0, 0, 0, 0, player_tiny ) class Player extends ecs.Entity new: (router, controller, alias) => @router = router @controller = controller if @router.state == "elected" -- We're the host player @alias = alias else error("Implement other players") class PlayerGraphicComponent extends world.GraphicsComponent @player_size = 1 @static = true new: (name, properties) => properties = properties or {} buf = am.buffer(6 * 3 * 4) buf.usage = "dynamic" @playerbuf = buf\view("vec3") @playerbuf[1] = vec3(0,0,0) @playerbuf[2] = vec3(0,@@player_size,0) @playerbuf[3] = vec3(@@player_size,@@player_size,0) @playerbuf[4] = vec3(@@player_size,@@player_size,0) @playerbuf[5] = vec3(@@player_size,0,0) @playerbuf[6] = vec3(0,0,0) properties.node = shim.player\append(am.depth_test("less")\append(am.bind({ MV: s_mv P: mat4(1) world_x: 0, world_y: 0, player: @playerbuf texuv: am.vec2_array({ vec2(0,0), vec2(0,1), vec2(1,1), vec2(1,1), vec2(1,0), vec2(0,0) }) dir: 0 textures: sprites.guy_diffuse.texture })\append(am.draw("triangles")))) properties.node\action(() => --print("Player graphic action") ) --print("Properties node is:", properties.node) super(name, properties) --print("finished init") @ move: (x,y) => assert(x, "x required") assert(y, "y required") h = @@player_size / 2 @playerbuf[1] = vec3(x-h,y-h,0) @playerbuf[2] = vec3(x-h,y+h,0) @playerbuf[3] = vec3(x+h,y+h,0) @playerbuf[4] = vec3(x+h,y+h,0) @playerbuf[5] = vec3(x+h,y-h,0) @playerbuf[6] = vec3(x-h,y-h,0) --print("Move called", @playerbuf[1]) face: (direction) => print("direction",direction) @properties.node("bind").dir = (direction ) % (math.pi * 2) --@properties.node("bind").MV = -- In a normal simulation, velocity adds acceleration * delta time every tick, minus some friction coefficient * current velocity -- i.e. velocity = (acceleration * delta) - (friction * velocity) -- every tick -- velocity[tick] = (acceleration * delta[tick]) - (friction * velocity[tick - 1]) -- velocity[4] = (acceleration * delta[4]) - (friction * velocity[3]) -- = (acceleration * delta[4]) - (friction * ((acceleration * delta[3]) - (friction * velocity[2]))) -- = (acceleration * delta[4]) - (friction * ((acceleration * delta[3]) - (friction * ((acceleration * delta[2]) - (friction * velocity[inital]))))) -- = (acceleration * delta[4]) - (friction * ((acceleration * delta[3]) - ((friction * acceleration * delta[2]) - (friction * friction * velocity[inital])))) -- = (acceleration * delta[4]) - (friciton * ((acceleration * delta[3]) - (friction * acceleration * delta[2]) + (friction^2 * velocity[inital]))) -- = (acceleration * delta[4]) - ((friction * acceleration * delta[3]) - (friction * friction * acceleration * delta[2]) + (friction^3 * velocity[inital])) -- = (acceleration * delta[4]) - (friction * acceleration * delta[3]) + (friction^2 * acceleration * delta[2]) - (friction^3 * velocity[inital]) -- as delta approaches 0 (high fidelity simulation), the middle components become e^(-friction * delta), and acceleration needs to be divided by friction -- Position is a second layer on top -- position[tick] = position[tick-1] + velocity[tick] -- position[2] = position[inital] + velocity[2] -- = position[inital] + (acceleration * delta[2]) - (friction * velocity[inital]) -- position[delta] = (delta * (acceleration / friction) ) - ((1 / friction) * (velocity[inital] - (acceleratin / friction)) * e^(-friction * delta) + position[inital] -- velocity = (acceleration * delta) - ( -- we want to find the location based on inital velocity and position, constant acceleration, and delta time friction = 0.1 class PlayerPredictedComponent extends ecs.PredictedComponent new: (name) => super(name, {vel: vec2(0,0), pos:vec2(0,0), accel: vec2(0,0)}, "net", { accel:() => vec2(@net.properties.accel) vel: () => --print("Net is ", @net.properties) delta = world.sync_time! - @net.properties.last_update (@net.properties.accel / friction) + ((@net.properties.vel - (@net.properties.accel / friction)) * math.exp(-friction * delta)) pos: () => delta = world.sync_time! - @net.properties.last_update friction_loss = @net.properties.accel / friction -- when delta = 0 (up to date) -- pos = (1/friction) * (velocity - friction_loss) * 1 + position -- = 2 * (2 - 2) * 1 + position -- = position (friction_loss * delta) - ((1/friction) * (@net.properties.vel - friction_loss) * (math.exp(-friction * delta))) + @properties.pos }) print("Right after creation, properties is",@properties) @node = am.group! join: (entity) => @gc = entity\get("graphic") @net = entity\get("net") @gc.properties.node\append(@node) s = @ @node\action(() => s\forward! ) forward: () => --print("Forward called", @properties) super! @gc\move(@properties.pos.x, @properties.pos.y) class ProtoPlayer extends ecs.Entity new: () => @controller = require("controllers.mouse_keyboard") cc = require("controllers.mouse_keyboard").Controller() gc = PlayerGraphicComponent("graphic") pc = PlayerPredictedComponent("pred") nc = ecs.NetworkedComponent("net",{accel: vec2(0,0), vel: vec2(0,0), pos: vec2(0,0), name: "test", last_update: 0, dir: 0}) print("Protoplayer created") super("test",{graphic:gc,net:nc,controller:cc,pred:pc}) {:Player, :ProtoPlayer}