camera
This commit is contained in:
parent
f97ac83d63
commit
96e4680904
|
@ -114,10 +114,11 @@ class Bot extends Pushable
|
|||
getDown: -> @orientation.rotate Vector.minusY
|
||||
getUp: -> @orientation.rotate Vector.unitY
|
||||
getDir: -> @orientation.rotate new Vector 0,0,@dir_sgn
|
||||
|
||||
getCurrentDir: -> @current_orientation.rotate(Vector.unitZ).normal()
|
||||
getCurrentUp: -> @current_orientation.rotate(Vector.unitY).normal()
|
||||
getCurrentLeft: -> @current_orientation.rotate(Vector.unitX).normal()
|
||||
|
||||
currentPos: -> @current_position.clone()
|
||||
currentDir: -> @current_orientation.rotate(Vector.unitZ).normal()
|
||||
currentUp: -> @current_orientation.rotate(Vector.unitY).normal()
|
||||
currentLeft: -> @current_orientation.rotate(Vector.unitX).normal()
|
||||
|
||||
# 0000000 000 00000000
|
||||
# 000 000 000 000
|
||||
|
|
|
@ -33,7 +33,7 @@ class Bullet extends Item
|
|||
@shootFromBot: (bot) ->
|
||||
bullet = new Bullet()
|
||||
world.addObject bullet
|
||||
bullet.direction = bot.getCurrentDir()
|
||||
bullet.direction = bot.currentDir()
|
||||
bullet.setPosition bot.position.plus bullet.direction.mul 0.8
|
||||
bullet.src_object = bot
|
||||
bullet.mesh.material.color.set bot.mesh.material.color
|
||||
|
|
241
coffee/camera.coffee
Normal file
241
coffee/camera.coffee
Normal file
|
@ -0,0 +1,241 @@
|
|||
|
||||
# 0000000 0000000 00 00 00000000 00000000 0000000
|
||||
# 000 000 000 000 000 000 000 000 000 000
|
||||
# 000 000000000 000000000 0000000 0000000 000000000
|
||||
# 000 000 000 000 0 000 000 000 000 000 000
|
||||
# 0000000 000 000 000 000 00000000 000 000 000 000
|
||||
{
|
||||
clamp
|
||||
} = require '/Users/kodi/s/ko/js/tools/tools'
|
||||
log = require '/Users/kodi/s/ko/js/tools/log'
|
||||
Matrix = require './lib/matrix'
|
||||
Vector = require './lib/vector'
|
||||
|
||||
class Camera extends Matrix
|
||||
|
||||
@INSIDE = 0
|
||||
@BEHIND = 1
|
||||
@FOLLOW = 2
|
||||
|
||||
constructor: (@player, opt) ->
|
||||
@fov = opt?.fov ? 90
|
||||
@near = opt?.near ? 0.01
|
||||
@eye_distance = @near
|
||||
@far = opt?.far ? 20
|
||||
@mode = Camera.BEHIND
|
||||
@aspect = opt.aspect ? -1
|
||||
@dist = 10
|
||||
@border = [0,0,0,0]
|
||||
|
||||
super
|
||||
|
||||
@setViewport 0.0, 0.0, 1.0, 1.0
|
||||
|
||||
@cam = new THREE.PerspectiveCamera @fov, @aspect, @near, @far
|
||||
@cam.position.z = @dist
|
||||
|
||||
step: (step) ->
|
||||
|
||||
switch @mode
|
||||
when Camera.INSIDE then @insideProjection()
|
||||
when Camera.BEHIND then @behindProjection()
|
||||
when Camera.FOLLOW then @followProjection()
|
||||
|
||||
camPos = @getPosition()
|
||||
@cam.position.copy camPos
|
||||
@cam.up.copy @getYVector()
|
||||
@cam.lookAt camPos.plus @getZVector()
|
||||
|
||||
if @light?
|
||||
pos = @getPosition().plus @light_offset
|
||||
@light.setDirection -@getZVector()
|
||||
@light.setPosition new Vector pos[X], pos[Y], pos[Z], 1.0 # positional light source
|
||||
|
||||
getLookAtPosition: -> @getZVector().mul(-@eye_distance).plus @getPosition()
|
||||
|
||||
updateViewport: ->
|
||||
ss = world.screenSize
|
||||
vp = []
|
||||
vp[0] = @viewport[0] * ss.w + @border[0]
|
||||
vp[1] = @viewport[1] * ss.h + @border[1]
|
||||
vp[2] = @viewport[2] * ss.w - @border[0] - @border[2]
|
||||
vp[3] = @viewport[3] * ss.h - @border[1] - @border[3]
|
||||
|
||||
setViewportBorder: (l, b, r, t) ->
|
||||
@border = [l,b,r,t]
|
||||
@updateViewport()
|
||||
|
||||
setViewport: (l, b, w, h) ->
|
||||
@viewport = [l,b,w,h]
|
||||
@updateViewport()
|
||||
|
||||
setFov: (fov) -> @fov = Math.max(2.0, Math.min fov, 175.0)
|
||||
|
||||
# 00000000 00000000 0000000 000 00000000 0000000 000000000 000 0000000 000 000
|
||||
# 000 000 000 000 000 000 000 000 000 000 000 000 000 0000 000
|
||||
# 00000000 0000000 000 000 000 0000000 000 000 000 000 000 000 0 000
|
||||
# 000 000 000 000 000 000 000 000 000 000 000 000 000 000 0000
|
||||
# 000 000 000 0000000 0000000 00000000 0000000 000 000 0000000 000 000
|
||||
|
||||
insideProjection: () ->
|
||||
|
||||
playerPos = @player.currentPos()
|
||||
playerDir = @player.currentDir()
|
||||
playerUp = @player.currentUp()
|
||||
lookAngle = @player.look_angle
|
||||
|
||||
posDelta = world.getSpeed() / 10.0 # smooth camera movement a little bit
|
||||
camPos = playerPos
|
||||
if lookAngle < 0
|
||||
camPos.add playerUp.mul -2*lookAngle/90
|
||||
@setPosition @getPosition().mul(1.0-posDelta).plus camPos.mul posDelta
|
||||
|
||||
if lookAngle # player is looking up or down
|
||||
@setXVector playerDir.cross(playerUp).normal()
|
||||
rot = Quaternion.rotationAroundVector lookAngle, @getXVector()
|
||||
@setYVector rot.rotate playerUp
|
||||
@setZVector rot.rotate playerDir #.neg()
|
||||
else
|
||||
# smooth camera rotation a little bit
|
||||
lookDelta = (2.0 - @getZVector().dot playerDir) * world.getSpeed() / 50.0
|
||||
newLookVector = @getZVector().mul(1.0 - lookDelta).plus playerDir.mul lookDelta
|
||||
newLookVector.normalize()
|
||||
@setXVector playerUp.cross(newLookVector).normal()
|
||||
@setYVector playerUp
|
||||
@setZVector newLookVector
|
||||
|
||||
@projection
|
||||
|
||||
# 0000000 00000000 000 000 000 000 000 0000000
|
||||
# 000 000 000 000 000 000 0000 000 000 000
|
||||
# 0000000 0000000 000000000 000 000 0 000 000 000
|
||||
# 000 000 000 000 000 000 000 0000 000 000
|
||||
# 0000000 00000000 000 000 000 000 000 0000000
|
||||
|
||||
behindProjection: () ->
|
||||
playerPos = @player.currentPos()
|
||||
playerDir = @player.currentDir()
|
||||
playerUp = @player.currentUp()
|
||||
lookAngle = @player.look_angle
|
||||
|
||||
# find a valid camera position
|
||||
botToCamera = playerUp.minus playerDir.mul 2
|
||||
min_f = botToCamera.length()
|
||||
botToCamera.normalize()
|
||||
|
||||
min_f = Math.min world.getWallDistanceForRay(playerPos, botToCamera), min_f
|
||||
camPos = playerPos.plus botToCamera.mul Math.max(min_f, 0.72) * (1-Math.abs(lookAngle)/90)
|
||||
if lookAngle < 0
|
||||
camPos.add playerUp.mul -2*lookAngle/90
|
||||
|
||||
camPos = world.getInsideWallPosWithDelta camPos, 0.2
|
||||
|
||||
# smooth camera movement a little bit
|
||||
posDelta = 0.2
|
||||
@setPosition @getPosition().mul(1.0 - posDelta).plus camPos.mul posDelta
|
||||
|
||||
if lookAngle
|
||||
# log "look_angle #{lookAngle}"
|
||||
@setXVector playerDir.cross(playerUp).normal()
|
||||
rot = Quaternion.rotationAroundVector lookAngle, @getXVector()
|
||||
@setYVector rot.rotate playerUp
|
||||
@setZVector rot.rotate playerDir #.neg()
|
||||
else
|
||||
# smooth camera rotation a little bit
|
||||
lookDelta = 0.3
|
||||
newLookVector = @getZVector().mul(1.0 - lookDelta).plus (playerDir.minus(playerUp.mul(0.2)).normal()).mul lookDelta
|
||||
newLookVector.normalize()
|
||||
|
||||
@setZVector newLookVector
|
||||
@setXVector playerUp.cross(newLookVector).normal()
|
||||
@setYVector newLookVector.cross(@getXVector()).normal()
|
||||
|
||||
# 00000000 0000000 000 000 0000000 000 000
|
||||
# 000 000 000 000 000 000 000 000 0 000
|
||||
# 000000 000 000 000 000 000 000 000000000
|
||||
# 000 000 000 000 000 000 000 000 000
|
||||
# 000 0000000 0000000 0000000 0000000 00 00
|
||||
|
||||
followProjection: () ->
|
||||
|
||||
camPos = @getPosition()
|
||||
desiredDistance = 2.0 # desired distance from camera to bot
|
||||
|
||||
playerPos = @player.currentPos()
|
||||
playerDir = @player.currentDir()
|
||||
playerUp = @player.currentUp()
|
||||
playerLeft = @player.currentLeft()
|
||||
|
||||
# first, adjust distance from camera to bot
|
||||
|
||||
botToCamera = camPos.minus playerPos # vector from bot to current pos
|
||||
cameraBotDistance = botToCamera.length() # distance from camera to bot
|
||||
|
||||
if cameraBotDistance >= desiredDistance
|
||||
difference = cameraBotDistance - desiredDistance
|
||||
delta = difference*difference/400.0 # weight for following speed
|
||||
camPos = camPos.mul(1.0-delta).plus playerPos.mul delta
|
||||
else
|
||||
difference = desiredDistance - cameraBotDistance
|
||||
delta = difference/20.0 # weight for negative following speed
|
||||
camPos = camPos.mul(1.0-delta).plus (playerPos.plus botToCamera.normal().mul desiredDistance).mul delta
|
||||
|
||||
# second, rotate around bot
|
||||
|
||||
botToCamera = camPos.minus playerPos
|
||||
botToCameraNormal = botToCamera.normal()
|
||||
|
||||
# rotate camera vertically
|
||||
verticalAngle = Vector.RAD2DEG Math.acos(clamp(-1.0, 1.0, botToCameraNormal.dot playerUp))
|
||||
if verticalAngle > 45
|
||||
# log "verticalAngle #{verticalAngle}"
|
||||
rotQuat = Quaternion.rotationAroundVector(verticalAngle/400.0, botToCameraNormal.cross(playerUp))
|
||||
botToCamera = rotQuat.rotate botToCamera
|
||||
botToCameraNormal = botToCamera.normal()
|
||||
camPos = playerPos.plus botToCamera
|
||||
|
||||
rotFactor = 1.0
|
||||
|
||||
wall_distance = world.getWallDistanceForPos camPos
|
||||
if wall_distance < 0.5 # try avoid piercing walls
|
||||
if wall_distance < 0.2
|
||||
camPos = world.getInsideWallPosWithDelta camPos, 0.2
|
||||
botToCamera = camPos.minus playerPos
|
||||
botToCameraNormal = botToCamera.normal()
|
||||
rotFactor = 0.5 / (wall_distance-0.2)
|
||||
|
||||
# try view bot from behind
|
||||
# calculate horizontal angle between bot orientation and vector to camera
|
||||
mappedToXZ = (botToCamera.minus playerUp.mul(botToCamera.dot playerUp)).normal()
|
||||
horizontalAngle = Vector.RAD2DEG Math.acos(clamp(-1.0, 1.0, -playerDir.dot mappedToXZ))
|
||||
if botToCameraNormal.dot(playerLeft) < 0
|
||||
horizontalAngle = -horizontalAngle
|
||||
rotQuat = Quaternion.rotationAroundVector horizontalAngle/(rotFactor*400.0), playerUp
|
||||
camPos = playerPos.plus rotQuat.rotate botToCamera
|
||||
|
||||
botToCamera = camPos.minus playerPos
|
||||
botToCameraNormal = botToCamera.normal()
|
||||
|
||||
@setPosition camPos # finally, set the position
|
||||
|
||||
# slowly adjust look direction by interpolating current and desired directions
|
||||
lookDelta = @getZVector().dot botToCameraNormal
|
||||
lookDelta *= lookDelta / 30.0
|
||||
newLookVector = @getZVector().mul(1.0-lookDelta).plus botToCameraNormal.neg().mul(lookDelta)
|
||||
newLookVector.normalize()
|
||||
|
||||
# slowly adjust up vector by interpolating current and desired up vectors
|
||||
upDelta = 1.5-@getYVector().dot playerUp
|
||||
upDelta *= upDelta / 100.0
|
||||
newUpVector = @getYVector().mul(1.0-upDelta).plus playerUp.mul(upDelta)
|
||||
newUpVector.normalize()
|
||||
|
||||
newLeftVector = newUpVector.cross newLookVector
|
||||
|
||||
# finished interpolations, update camera matrix
|
||||
@setXVector newLeftVector
|
||||
@setYVector newUpVector
|
||||
@setZVector newLookVector
|
||||
@projection
|
||||
|
||||
module.exports = Camera
|
|
@ -1,119 +0,0 @@
|
|||
# 00000000 00000000 00000000 0000000 00000000 00000000 0000000 000000000 000 000 000 00000000
|
||||
# 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
|
||||
# 00000000 0000000 0000000 0000000 00000000 0000000 000 000 000 000 000 0000000
|
||||
# 000 000 000 000 000 000 000 000 000 000 000 000
|
||||
# 000 00000000 000 000 0000000 000 00000000 0000000 000 000 0 00000000
|
||||
{
|
||||
clamp
|
||||
} = require '/Users/kodi/s/ko/js/tools/tools'
|
||||
log = require '/Users/kodi/s/ko/js/tools/log'
|
||||
Matrix = require './lib/matrix'
|
||||
|
||||
class Perspective extends Matrix
|
||||
|
||||
constructor: (fov,near=0.01,far=1000) ->
|
||||
@znear = near
|
||||
@zfar = far
|
||||
@fov = fov
|
||||
@aspect_ratio = -1.0
|
||||
@eye_distance = @znear
|
||||
# @eye_distance = 5.0
|
||||
@border = [0,0,0,0]
|
||||
@setViewport 0.0, 0.0, 1.0, 1.0
|
||||
super
|
||||
# log "Perspective #{@fov} #{@znear} #{@zfar}"
|
||||
|
||||
reset: ->
|
||||
@fov = 60.0
|
||||
@eye_distance = @znear
|
||||
super
|
||||
@translate 0, 0, @eye_distance
|
||||
|
||||
# rotate: (x,y,z) ->
|
||||
# savePos = @getLookAtPosition()
|
||||
# @translate -@getPosition()
|
||||
#
|
||||
# up = @getYVector()
|
||||
# look = @getZVector()
|
||||
#
|
||||
# rotxz = Matrix.rotation x, 0.0, z
|
||||
# roty = Matrix.rotation 0.0, y, 0.0
|
||||
#
|
||||
# yunit = new Vector 0.0, 1.0, 0.0
|
||||
# zunit = new Vector 0.0, 0.0, 1.0
|
||||
#
|
||||
# lookperp = @look.perpendicular yunit # y-axis rotation
|
||||
# if lookperp.length() > 0
|
||||
# look = roty.transform lookperp.plus look.parallel(yunit)
|
||||
# up = roty.transform up.perpendicular(yunit).plus up.parallel(yunit)
|
||||
#
|
||||
# # x & z-axis rotation
|
||||
# transmat = new Matrix up.cross(look), up, look
|
||||
#
|
||||
# uprotxz = rotxz.transform yunit
|
||||
# lookrotxz = rotxz.transform zunit
|
||||
#
|
||||
# up = transmat.transform uprotxz
|
||||
# look = transmat.transform lookrotxz
|
||||
#
|
||||
# @.initXYZ up.cross(look), up, look
|
||||
#
|
||||
# @setPosition savePos.plus @getZVector().mul @eye_distance
|
||||
|
||||
apply: (camera) ->
|
||||
camPos = @getPosition()
|
||||
camera.position.copy camPos
|
||||
camera.up.copy @getYVector()
|
||||
camera.lookAt camPos.plus @getZVector()
|
||||
|
||||
if @light?
|
||||
pos = @getPosition().plus @light_offset
|
||||
@light.setDirection -@getZVector()
|
||||
@light.setPosition new Vector pos[X], pos[Y], pos[Z], 1.0 # positional light source
|
||||
|
||||
# setEyeDistance: (distance) ->
|
||||
# log 'setEyeDistance', distance
|
||||
# lookAtPos = @getLookAtPosition()
|
||||
# @eye_distance = Math.min Math.max(@znear, distance), 0.9*@zfar
|
||||
# @setPosition lookAtPos.plus @getZVector().mul @eye_distance
|
||||
|
||||
# setLookAtPosition: (lookAtPos) ->
|
||||
# up = @getYVector()
|
||||
# newLook = lookAtPos.minus(@getPosition()).normal()
|
||||
# newRight = up.cross(newLook).normal()
|
||||
# newUp = newLook.cross(newRight).normal()
|
||||
#
|
||||
# @setXVector newRight
|
||||
# @setYVector newUp
|
||||
# @setZVector newLook
|
||||
# # log 'setLookAtPosition', @matrix
|
||||
# @eye_distance = lookAtPos.minus(@getPosition()).length()
|
||||
|
||||
getLookAtPosition: -> @getZVector().mul(-@eye_distance).plus @getPosition()
|
||||
|
||||
updateViewport: ->
|
||||
ss = world.screenSize
|
||||
vp = []
|
||||
vp[0] = @viewport[0] * ss.w + @border[0]
|
||||
vp[1] = @viewport[1] * ss.h + @border[1]
|
||||
vp[2] = @viewport[2] * ss.w - @border[0] - @border[2]
|
||||
vp[3] = @viewport[3] * ss.h - @border[1] - @border[3]
|
||||
|
||||
getCurrentAspectRatio: ->
|
||||
vps = @getViewportSize()
|
||||
@aspect_ratio <= 0.0 and vps.w/vps.h or @aspect_ratio
|
||||
|
||||
getScreenCoordinates: (pos, sx, sy) ->
|
||||
|
||||
setViewportBorder: (l, b, r, t) ->
|
||||
@border = [l,b,r,t]
|
||||
@updateViewport()
|
||||
|
||||
setViewport: (l, b, w, h) ->
|
||||
@viewport = [l,b,w,h]
|
||||
@updateViewport()
|
||||
|
||||
setFov: (fov) -> @fov = Math.max(2.0, Math.min fov, 175.0)
|
||||
|
||||
module.exports = Perspective
|
||||
|
|
@ -12,8 +12,8 @@ Bot = require './bot'
|
|||
Action = require './action'
|
||||
Timer = require './timer'
|
||||
Vector = require './lib/vector'
|
||||
Camera = require './camera'
|
||||
Quaternion = require './lib/quaternion'
|
||||
Perspective = require './perspective'
|
||||
|
||||
class Player extends Bot
|
||||
|
||||
|
@ -33,6 +33,9 @@ class Player extends Bot
|
|||
view: 'c'
|
||||
push: 'shift'
|
||||
|
||||
@camera = new Camera @,
|
||||
aspect: world.view.offsetWidth / world.view.offsetHeight
|
||||
|
||||
@look_action = null
|
||||
@look_angle = 0.0
|
||||
@new_dir_sgn = 1.0
|
||||
|
@ -47,178 +50,8 @@ class Player extends Bot
|
|||
|
||||
@addEventWithName "landed"
|
||||
|
||||
@projection = new Perspective 90.0
|
||||
@projection.updateViewport()
|
||||
|
||||
bulletHitSound: -> 'BULLET_HIT_PLAYER'
|
||||
|
||||
# 00000000 00000000 0000000 000 00000000 0000000 000000000 000 0000000 000 000
|
||||
# 000 000 000 000 000 000 000 000 000 000 000 000 000 0000 000
|
||||
# 00000000 0000000 000 000 000 0000000 000 000 000 000 000 000 0 000
|
||||
# 000 000 000 000 000 000 000 000 000 000 000 000 000 000 0000
|
||||
# 000 000 000 0000000 0000000 00000000 0000000 000 000 0000000 000 000
|
||||
|
||||
getInsideProjection: () ->
|
||||
|
||||
# smooth camera movement a little bit
|
||||
posDelta = world.getSpeed() / 10.0
|
||||
playerDir = @getCurrentDir()
|
||||
playerUp = @current_orientation.rotate(new Vector(0,1,0)).normal()
|
||||
camPos = @current_position.clone()
|
||||
if @look_angle < 0
|
||||
camPos.add playerUp.mul -2*@look_angle/90
|
||||
@projection.setPosition @projection.getPosition().mul(1.0-posDelta).plus camPos.mul posDelta
|
||||
|
||||
if @look_angle # player is looking up or down
|
||||
@projection.setXVector playerDir.cross(playerUp).normal()
|
||||
rot = Quaternion.rotationAroundVector @look_angle, @projection.getXVector()
|
||||
@projection.setYVector rot.rotate playerUp
|
||||
@projection.setZVector rot.rotate playerDir #.neg()
|
||||
else
|
||||
# smooth camera rotation a little bit
|
||||
lookDelta = (2.0 - @projection.getZVector().dot playerDir) * world.getSpeed() / 50.0
|
||||
newLookVector = @projection.getZVector().mul(1.0 - lookDelta).plus playerDir.mul lookDelta
|
||||
newLookVector.normalize()
|
||||
@projection.setXVector playerUp.cross(newLookVector).normal()
|
||||
@projection.setYVector playerUp
|
||||
@projection.setZVector newLookVector
|
||||
|
||||
@projection
|
||||
|
||||
# 0000000 00000000 000 000 000 000 000 0000000
|
||||
# 000 000 000 000 000 000 0000 000 000 000
|
||||
# 0000000 0000000 000000000 000 000 0 000 000 000
|
||||
# 000 000 000 000 000 000 000 0000 000 000
|
||||
# 0000000 00000000 000 000 000 000 000 0000000
|
||||
|
||||
getBehindProjection: () ->
|
||||
|
||||
playerDir = @getCurrentDir()
|
||||
playerUp = @current_orientation.rotate(new Vector(0,1,0)).normal()
|
||||
|
||||
# find a valid camera position
|
||||
botToCamera = playerUp.minus playerDir.mul 2
|
||||
min_f = botToCamera.length()
|
||||
botToCamera.normalize()
|
||||
|
||||
min_f = Math.min world.getWallDistanceForRay(@current_position, botToCamera), min_f
|
||||
camPos = @current_position.plus botToCamera.mul Math.max(min_f, 0.72) * (1-Math.abs(@look_angle)/90)
|
||||
if @look_angle < 0
|
||||
camPos.add playerUp.mul -2*@look_angle/90
|
||||
|
||||
camPos = world.getInsideWallPosWithDelta camPos, 0.2
|
||||
|
||||
# smooth camera movement a little bit
|
||||
posDelta = 0.2
|
||||
@projection.setPosition @projection.getPosition().mul(1.0 - posDelta).plus camPos.mul posDelta
|
||||
|
||||
if @look_angle
|
||||
# log "look_angle #{@look_angle}"
|
||||
@projection.setXVector playerDir.cross(playerUp).normal()
|
||||
rot = Quaternion.rotationAroundVector @look_angle, @projection.getXVector()
|
||||
@projection.setYVector rot.rotate playerUp
|
||||
@projection.setZVector rot.rotate playerDir #.neg()
|
||||
else
|
||||
# smooth camera rotation a little bit
|
||||
lookDelta = 0.3
|
||||
newLookVector = @projection.getZVector().mul(1.0 - lookDelta).plus (playerDir.minus(@getCurrentUp().mul(0.2)).normal()).mul lookDelta
|
||||
newLookVector.normalize()
|
||||
|
||||
@projection.setZVector newLookVector
|
||||
@projection.setXVector playerUp.cross(newLookVector).normal()
|
||||
@projection.setYVector newLookVector.cross(@projection.getXVector()).normal()
|
||||
|
||||
# log 'Player.getBehindProjection', @projection.getPosition()
|
||||
@projection
|
||||
|
||||
# 00000000 0000000 000 000 0000000 000 000
|
||||
# 000 000 000 000 000 000 000 000 0 000
|
||||
# 000000 000 000 000 000 000 000 000000000
|
||||
# 000 000 000 000 000 000 000 000 000
|
||||
# 000 0000000 0000000 0000000 0000000 00 00
|
||||
|
||||
getFollowProjection: () ->
|
||||
|
||||
camPos = @projection.getPosition()
|
||||
desiredDistance = 2.0 # desired distance from camera to bot
|
||||
|
||||
playerPos = @current_position
|
||||
playerDir = @getCurrentDir()
|
||||
playerUp = @getCurrentUp()
|
||||
playerLeft = @getCurrentLeft()
|
||||
|
||||
# first, adjust distance from camera to bot
|
||||
|
||||
botToCamera = camPos.minus playerPos # vector from bot to current pos
|
||||
cameraBotDistance = botToCamera.length() # distance from camera to bot
|
||||
|
||||
if cameraBotDistance >= desiredDistance
|
||||
difference = cameraBotDistance - desiredDistance
|
||||
delta = difference*difference/400.0 # weight for following speed
|
||||
camPos = camPos.mul(1.0-delta).plus playerPos.mul delta
|
||||
else
|
||||
difference = desiredDistance - cameraBotDistance
|
||||
delta = difference/20.0 # weight for negative following speed
|
||||
camPos = camPos.mul(1.0-delta).plus (playerPos.plus botToCamera.normal().mul desiredDistance).mul delta
|
||||
|
||||
# second, rotate around bot
|
||||
|
||||
botToCamera = camPos.minus playerPos
|
||||
botToCameraNormal = botToCamera.normal()
|
||||
|
||||
# rotate camera vertically
|
||||
verticalAngle = Vector.RAD2DEG Math.acos(clamp(-1.0, 1.0, botToCameraNormal.dot playerUp))
|
||||
if verticalAngle > 45
|
||||
# log "verticalAngle #{verticalAngle}"
|
||||
rotQuat = Quaternion.rotationAroundVector(verticalAngle/400.0, botToCameraNormal.cross(playerUp))
|
||||
botToCamera = rotQuat.rotate botToCamera
|
||||
botToCameraNormal = botToCamera.normal()
|
||||
camPos = playerPos.plus botToCamera
|
||||
|
||||
rotFactor = 1.0
|
||||
|
||||
wall_distance = world.getWallDistanceForPos camPos
|
||||
if wall_distance < 0.5 # try avoid piercing walls
|
||||
if wall_distance < 0.2
|
||||
camPos = world.getInsideWallPosWithDelta camPos, 0.2
|
||||
botToCamera = camPos.minus playerPos
|
||||
botToCameraNormal = botToCamera.normal()
|
||||
rotFactor = 0.5 / (wall_distance-0.2)
|
||||
|
||||
# try view bot from behind
|
||||
# calculate horizontal angle between bot orientation and vector to camera
|
||||
mappedToXZ = (botToCamera.minus playerUp.mul(botToCamera.dot playerUp)).normal()
|
||||
horizontalAngle = Vector.RAD2DEG Math.acos(clamp(-1.0, 1.0, -playerDir.dot mappedToXZ))
|
||||
if botToCameraNormal.dot(playerLeft) < 0
|
||||
horizontalAngle = -horizontalAngle
|
||||
rotQuat = Quaternion.rotationAroundVector horizontalAngle/(rotFactor*400.0), playerUp
|
||||
camPos = playerPos.plus rotQuat.rotate botToCamera
|
||||
|
||||
botToCamera = camPos.minus playerPos
|
||||
botToCameraNormal = botToCamera.normal()
|
||||
|
||||
@projection.setPosition camPos # finally, set the position
|
||||
|
||||
# slowly adjust look direction by interpolating current and desired directions
|
||||
lookDelta = @projection.getZVector().dot botToCameraNormal
|
||||
lookDelta *= lookDelta / 30.0
|
||||
newLookVector = @projection.getZVector().mul(1.0-lookDelta).plus botToCameraNormal.neg().mul(lookDelta)
|
||||
newLookVector.normalize()
|
||||
|
||||
# slowly adjust up vector by interpolating current and desired up vectors
|
||||
upDelta = 1.5-@projection.getYVector().dot playerUp
|
||||
upDelta *= upDelta / 100.0
|
||||
newUpVector = @projection.getYVector().mul(1.0-upDelta).plus playerUp.mul(upDelta)
|
||||
newUpVector.normalize()
|
||||
|
||||
newLeftVector = newUpVector.cross newLookVector
|
||||
|
||||
# finished interpolations, update camera matrix
|
||||
@projection.setXVector newLeftVector
|
||||
@projection.setYVector newUpVector
|
||||
@projection.setZVector newLookVector
|
||||
@projection
|
||||
|
||||
# 0000000 0000000 000000000 000 0000000 000 000
|
||||
# 000 000 000 000 000 000 000 0000 000
|
||||
# 000000000 000 000 000 000 000 000 0 000
|
||||
|
@ -419,30 +252,4 @@ class Player extends Bot
|
|||
|
||||
false
|
||||
|
||||
# 0000000 000 0000000 00000000 000 0000000 000 000
|
||||
# 000 000 000 000 000 000 000 000 000 000 000
|
||||
# 000 000 000 0000000 00000000 000 000000000 00000
|
||||
# 000 000 000 000 000 000 000 000 000
|
||||
# 0000000 000 0000000 000 0000000 000 000 000
|
||||
|
||||
step: (step) -> super step
|
||||
|
||||
getBodyColor: () ->
|
||||
if world.getCameraMode() == world.CAMERA_BEHIND
|
||||
# static bodyColor
|
||||
bodyColor = colors[KikiPlayer_base_color]
|
||||
bodyColor.setAlpha(kMin(0.7, (@projection.getPosition()-@current_position).length()-0.4))
|
||||
return bodyColor
|
||||
|
||||
return colors[KikiPlayer_base_color]
|
||||
|
||||
getTireColor: () ->
|
||||
if world.getCameraMode() == world.CAMERA_BEHIND
|
||||
# static tireColor
|
||||
tireColor = colors[KikiPlayer_tire_color]
|
||||
tireColor.setAlpha(kMin(1.0, (@projection.getPosition()-@current_position).length()-0.4))
|
||||
return tireColor
|
||||
|
||||
return colors[KikiPlayer_tire_color]
|
||||
|
||||
module.exports = Player
|
||||
|
|
|
@ -15,6 +15,7 @@ Pos = require './lib/pos'
|
|||
Size = require './lib/size'
|
||||
Cell = require './cell'
|
||||
Gate = require './gate'
|
||||
Camera = require './camera'
|
||||
Light = require './light'
|
||||
Levels = require './levels'
|
||||
Player = require './player'
|
||||
|
@ -43,10 +44,6 @@ Face} = require './items'
|
|||
world = null
|
||||
|
||||
class World extends Actor
|
||||
|
||||
@CAMERA_INSIDE = 0
|
||||
@CAMERA_BEHIND = 1
|
||||
@CAMERA_FOLLOW = 2
|
||||
|
||||
@levels = null
|
||||
|
||||
|
@ -63,10 +60,7 @@ class World extends Actor
|
|||
|
||||
@speed = 6
|
||||
|
||||
@raster_size = 0.05
|
||||
# @camera_mode = World.CAMERA_INSIDE
|
||||
@camera_mode = World.CAMERA_BEHIND
|
||||
# @camera_mode = World.CAMERA_FOLLOW
|
||||
@rasterSize = 0.05
|
||||
|
||||
super
|
||||
|
||||
|
@ -84,22 +78,7 @@ class World extends Actor
|
|||
@renderer.setClearColor 0x000000
|
||||
@renderer.setSize @view.offsetWidth, @view.offsetHeight
|
||||
@renderer.shadowMap.type = THREE.PCFSoftShadowMap
|
||||
|
||||
# 0000000 0000000 00 00 00000000 00000000 0000000
|
||||
# 000 000 000 000 000 000 000 000 000 000
|
||||
# 000 000000000 000000000 0000000 0000000 000000000
|
||||
# 000 000 000 000 0 000 000 000 000 000 000
|
||||
# 0000000 000 000 000 000 00000000 000 000 000 000
|
||||
|
||||
@fov = 90
|
||||
@near = 0.1
|
||||
@far = 20
|
||||
@aspect = @view.offsetWidth / @view.offsetHeight
|
||||
@dist = 10
|
||||
|
||||
@camera = new THREE.PerspectiveCamera @fov, @aspect, @near, @far
|
||||
@camera.position.z = @dist
|
||||
|
||||
|
||||
# 0000000 0000000 00000000 000 000 00000000
|
||||
# 000 000 000 0000 000 000
|
||||
# 0000000 000 0000000 000 0 000 0000000
|
||||
|
@ -115,7 +94,7 @@ class World extends Actor
|
|||
# 0000000 000 0000000 000 000 000
|
||||
|
||||
@sun = new THREE.PointLight 0xffffff
|
||||
@sun.position.copy @camera.position
|
||||
@sun.position.copy @player.camera.getPosition() if @player?
|
||||
@scene.add @sun
|
||||
|
||||
@ambient = new THREE.AmbientLight 0x111111
|
||||
|
@ -199,11 +178,6 @@ class World extends Actor
|
|||
# else
|
||||
# @setName "noname"
|
||||
|
||||
# if @preview
|
||||
# @getProjection().setViewport(0.0, 0.4, 1.0, 0.6)
|
||||
# else
|
||||
# @getProjection().setViewport(0.0, 0.0, 1.0, 1.0)
|
||||
|
||||
# ............................................................ escape
|
||||
# escape_event = Controller.getEventWithName ("escape")
|
||||
# escape_event.removeAllActions()
|
||||
|
@ -251,7 +225,7 @@ class World extends Actor
|
|||
else if @dict.player.coordinates?
|
||||
@addObjectAtPos @player, new Pos @dict.player.coordinates
|
||||
|
||||
@getProjection().setPosition new Vector 0,0,0
|
||||
@player.camera.setPosition new Vector 0,0,0
|
||||
|
||||
restart: () -> @create @dict
|
||||
|
||||
|
@ -344,10 +318,10 @@ class World extends Actor
|
|||
# calcuate max distance (for position relative sound)
|
||||
@max_distance = Math.max(@size.x, Math.max(@size.y, @size.z)) # heuristic of a heuristic :-)
|
||||
@cage?.del()
|
||||
@cage = new Cage @size, @raster_size
|
||||
@cage = new Cage @size, @rasterSize
|
||||
|
||||
getCellAtPos: (pos) -> return @cells[@posToIndex(pos)] if @isValidPos pos
|
||||
getBotAtPos: (pos) -> @getObjectOfTypeAtPos KikiBot, new Pos pos
|
||||
getBotAtPos: (pos) -> @getObjectOfTypeAtPos Bot, new Pos pos
|
||||
|
||||
posToIndex: (pos) ->
|
||||
p = new Pos pos
|
||||
|
@ -477,9 +451,7 @@ class World extends Actor
|
|||
|
||||
newObject: (object) ->
|
||||
if _.isString object
|
||||
if object.startsWith 'Kiki'
|
||||
return new (require "./#{object.slice(4).toLowerCase()}")()
|
||||
else if object.startsWith 'new'
|
||||
if object.startsWith 'new'
|
||||
return eval object
|
||||
return new (require "./#{object.toLowerCase()}")()
|
||||
if object instanceof Item
|
||||
|
@ -548,9 +520,9 @@ class World extends Actor
|
|||
log "World.getObjectWithName [WARNING] no object with name #{objectName}"
|
||||
null
|
||||
|
||||
setCameraMode: (mode) -> @camera_mode = clamp World.CAMERA_INSIDE, World.CAMERA_FOLLOW, mode
|
||||
setCameraMode: (mode) -> @player.camera.mode = clamp Camera.INSIDE, Camera.FOLLOW, mode
|
||||
|
||||
changeCameraMode: -> @camera_mode = (@camera_mode+1) % (World.CAMERA_FOLLOW+1)
|
||||
changeCameraMode: -> @player.camera.mode = (@player.camera.mode+1) % (Camera.FOLLOW+1)
|
||||
|
||||
# 0000000 0000000 000 00 00 0000000 000 000 00000000
|
||||
# 000 000 000 000 000 000 000 000 000 000 000 000
|
||||
|
@ -638,14 +610,6 @@ class World extends Actor
|
|||
else
|
||||
log "world.objectMoved [WARNING] #{movedObject.name} no target cell?"
|
||||
|
||||
setObjectColor: (color_name, color) ->
|
||||
if color_name == 'base'
|
||||
# KikiWall::setObjectColor "base", color
|
||||
@colors[0] = color
|
||||
else if color_name == 'plate'
|
||||
# KikiWall::setObjectColor "plate", color
|
||||
@colors[1] = color
|
||||
|
||||
# 0000000 000000000 00000000 00000000
|
||||
# 000 000 000 000 000
|
||||
# 0000000 000 0000000 00000000
|
||||
|
@ -653,31 +617,27 @@ class World extends Actor
|
|||
# 0000000 000 00000000 000
|
||||
|
||||
step: (step) ->
|
||||
camera = @player.camera.cam
|
||||
if false
|
||||
quat = @camera.quaternion.clone()
|
||||
quat = camera.quaternion.clone()
|
||||
quat.multiply new THREE.Quaternion().setFromAxisAngle new THREE.Vector3(1,0,0), step.dsecs*0.2
|
||||
quat.multiply new THREE.Quaternion().setFromAxisAngle new THREE.Vector3(0,1,0), step.dsecs*0.1
|
||||
center = @size.div 2
|
||||
@camera.position.set(center.x,center.y,center.z+@dist).applyQuaternion quat
|
||||
@camera.quaternion.copy quat
|
||||
camera.position.set(center.x,center.y,center.z+@dist).applyQuaternion quat
|
||||
camera.quaternion.copy quat
|
||||
|
||||
Timer.event.triggerActions()
|
||||
Timer.event.finishActions()
|
||||
|
||||
o.step?(step) for o in @objects
|
||||
@player.camera.step step
|
||||
|
||||
switch @camera_mode
|
||||
when World.CAMERA_INSIDE then @projection = @player.getInsideProjection()
|
||||
when World.CAMERA_BEHIND then @projection = @player.getBehindProjection()
|
||||
when World.CAMERA_FOLLOW then @projection = @player.getFollowProjection()
|
||||
|
||||
Sound.setMatrix @projection
|
||||
Sound.setMatrix @player.camera
|
||||
|
||||
# Material.tire.visible = @camera_mode != World.CAMERA_INSIDE
|
||||
@player.setOpacity clamp 0, 1, @projection.getPosition().minus(@player.current_position).length()-0.4
|
||||
@projection.apply @camera
|
||||
@sun.position.copy @camera.position
|
||||
@renderer.render @scene, @camera
|
||||
@player.setOpacity clamp 0, 1, @player.camera.getPosition().minus(@player.current_position).length()-0.4
|
||||
|
||||
@sun.position.copy camera.position
|
||||
@renderer.render @scene, camera
|
||||
|
||||
# 000000000 000 00 00 00000000
|
||||
# 000 000 000 000 000
|
||||
|
@ -711,8 +671,9 @@ class World extends Actor
|
|||
|
||||
resized: (w,h) ->
|
||||
@aspect = w/h
|
||||
@camera?.aspect = @aspect
|
||||
@camera?.updateProjectionMatrix()
|
||||
camera = @player.camera.cam
|
||||
camera?.aspect = @aspect
|
||||
camera?.updateProjectionMatrix()
|
||||
@renderer?.setSize w,h
|
||||
@screenSize = new Size w,h
|
||||
|
||||
|
@ -819,7 +780,7 @@ class World extends Actor
|
|||
if less_text
|
||||
page.getEventWithName("previous").addAction (i=index-1) => @outro i
|
||||
|
||||
resetProjection: -> world.getProjection().setViewport 0.0, 0.0, 1.0, 1.0
|
||||
resetProjection: -> @player.camera.setViewport 0.0, 0.0, 1.0, 1.0
|
||||
|
||||
# 00000000 0000000 0000000
|
||||
# 000 000 000
|
||||
|
@ -891,15 +852,7 @@ class World extends Actor
|
|||
displayLights: () ->
|
||||
for light in @lights
|
||||
lignt.display()
|
||||
|
||||
getProjection: () ->
|
||||
if not @projection
|
||||
switch @camera_mode
|
||||
when World.CAMERA_INSIDE then @projection = @player.getInsideProjection()
|
||||
when World.CAMERA_BEHIND then @projection = @player.getBehindProjection()
|
||||
when World.CAMERA_FOLLOW then @projection = @player.getFollowProjection()
|
||||
@projection
|
||||
|
||||
|
||||
playSound: (sound, pos, time) -> Sound.play sound, pos, time
|
||||
|
||||
# 000 000 00000000 000 000
|
||||
|
|
Loading…
Reference in New Issue
Block a user