diff --git a/coffee/action.coffee b/coffee/action.coffee index fb1e1ea..4428e95 100644 --- a/coffee/action.coffee +++ b/coffee/action.coffee @@ -51,19 +51,6 @@ class Action @delete_flag_ptr = false @reset() -# KikiAction (KikiActionObject* o, int d, int m ) -# { - # action_object = o - # action_id = 0 - # mode = m - # duration = d - # event = null - - # delete_flag_ptr = null - - # @reset() -# } - del: -> if @event then @event.removeAction @ if @object then @object.removeAction @ @@ -102,7 +89,7 @@ class Action performWithEvent: (event) -> eventTime = event.getTime() - + log "action.performWithEvent #{@name} eventTime #{eventTime}" if @start == 0 @start = eventTime @current = 0 @@ -112,7 +99,6 @@ class Action @perform() @last = @current @finished() if @duration == 0 and @mode == Action.ONCE - else currentDiff = eventTime - @start if currentDiff >= @getDuration() diff --git a/coffee/bot.coffee b/coffee/bot.coffee index 23e6a25..49b711e 100644 --- a/coffee/bot.coffee +++ b/coffee/bot.coffee @@ -74,6 +74,11 @@ class Bot extends Pushable @startTimedAction @getActionWithId(Action.NOOP), 500 + + getDown: -> @orientation.rotate(new Vector 0,1,0).neg() + getUp: -> @orientation.rotate(new Vector 0,1,0) + getDir: -> @orientation.rotate(new Vector 0,0,1).mul @dir_sgn + addMoves: (m) -> @moves += m addHealth: (h) -> @health = Math.max @health+h @@ -143,7 +148,8 @@ class Bot extends Pushable relTime = action.getRelativeTime() dltTime = action.getRelativeDelta() - log "performAction #{action.name} #{relTime} #{dltTime} id #{actionId}" + log "Bot.performAction #{action.name} #{action.current} #{action.last} #{action.duration} id #{actionId}" + log "Bot.performAction #{action.name} #{relTime} #{dltTime} id #{actionId}" switch actionId when Action.SHOOT @@ -212,10 +218,10 @@ class Bot extends Pushable if @move_action == null and relTime == 0.0 # if not performing move action and start of rotation # update @orientation now, so next move action will move in desired @direction if actionId == Action.TURN_LEFT - @orientation *= Quaternion.rotationAroundVector 90.0, new Vector 0,1,0 + @orientation = @orientation.mul Quaternion.rotationAroundVector 90.0, new Vector 0,1,0 @rest_orientation = Quaternion.rotationAroundVector -90.0, new Vector 0,1,0 else - @orientation *= Quaternion.rotationAroundVector -90.0, new Vector 0,1,0 + @orientation = @orientation.mul Quaternion.rotationAroundVector -90.0, new Vector 0,1,0 @rest_orientation = Quaternion.rotationAroundVector 90.0, new Vector 0,1,0 if actionId == Action.TURN_LEFT @@ -247,7 +253,7 @@ class Bot extends Pushable if actionId == Action.TURN_LEFT or actionId == Action.TURN_RIGHT @rotate_action = null - if move_action # bot currently performing a move action -> store rotation in @rest_orientation + if @move_action # bot currently performing a move action -> store rotation in @rest_orientation @rest_orientation = @rest_orientation.mul @rotate_orientation @rotate_orientation.reset() else @@ -280,19 +286,18 @@ class Bot extends Pushable actionFinished: (action) -> actionId = action.id - if @isDead() - die() if not @died - + if not @died + @die() if actionId != Action.PUSH and actionId != Action.FALL # dead player may only fall, nothing else return if @spiked @move_action = null - @startTimedAction getActionWithId(Action.NOOP), 0 + @startTimedAction @getActionWithId(Action.NOOP), 0 return - if actionId == Action.PUSH or @direction != KVector() + if actionId == Action.PUSH or not @direction.isZero() super action return @@ -312,22 +317,22 @@ class Bot extends Pushable @move_action = @getActionWithId Action.FORWARD world.playSound 'BOT_LAND', @getPos(), 0.25 else # forward will not be empty - if world.isUnoccupiedPos position.minus @getUp() # below is empty + if world.isUnoccupiedPos @position.minus @getUp() # below is empty @move_action = @getActionWithId Action.CLIMB_UP world.playSound 'BOT_LAND', @getPos(), 0.5 - else if world.isUnoccupiedPos position.minus @getUp() # below will be empty + else if world.isUnoccupiedPos @position.minus @getUp() # below will be empty if move # sticky if moving - if world.isUnoccupiedPos position.plus @getDir() + if world.isUnoccupiedPos @position.plus @getDir() # forward will be empty - if world.isOccupiedPos position.plus @getDir().minus @getUp() + if world.isOccupiedPos @position.plus @getDir().minus @getUp() # below forward is solid - occupant = world.getOccupantAtPos position.plus @getDir().minus @getUp() + occupant = world.getOccupantAtPos @position.plus @getDir().minus @getUp() if occupant == null or not occupant.isSlippery() - @move_action = @getActionWithId (Action.FORWARD) + @move_action = @getActionWithId Action.FORWARD else occupant = world.getOccupantAtPos position.plus @getDir() if occupant == null or not occupant.isSlippery() - @move_action = @getActionWithId (Action.CLIMB_UP) + @move_action = @getActionWithId Action.CLIMB_UP if @move_action == null @move_action = @getActionWithId Action.FALL @@ -354,9 +359,10 @@ class Bot extends Pushable moveBot: () -> @move_action = null - + log "bot.moveBot @position", @position + log "bot.moveBot @getDir", @getDir() forwardPos = @position.plus @getDir() - + log "bot.moveBot", forwardPos if @jump or @jump_once and # jump mode or jump activated while moving @dir_sgn == 1.0 and # and moving forward world.isUnoccupiedPos @position.plus @getUp() # and above empty @@ -366,12 +372,14 @@ class Bot extends Pushable else # no space to jump forward -> jump up @move_action = @getActionWithId Action.JUMP else if world.isUnoccupiedPos forwardPos # forward is empty + log 'forward is empty' if world.isUnoccupiedPos forwardPos.plus @getDown() # below forward also empty @move_action = @getActionWithId Action.CLIMB_DOWN else # forward down is solid @move_action = @getActionWithId Action.FORWARD else # forward is not empty + log 'forward is not empty' moveAction = @getActionWithId Action.FORWARD if @push and world.mayObjectPushToPos @, forwardPos, moveAction.getDuration() moveAction.reset() diff --git a/coffee/cell.coffee b/coffee/cell.coffee index 9081234..036e0b2 100644 --- a/coffee/cell.coffee +++ b/coffee/cell.coffee @@ -12,7 +12,7 @@ class Cell constructor: () -> @objects = [] getObjectsOfType: (clss) -> @objects.filter (o) -> o instanceof clss - getObjectOfType: (clss) -> _.find @objects, (o) -> o instanceof clss + getObjectOfType: (clss) -> _.find @objects, (o) -> o instanceof clss getRealObjectOfType: (clss) -> _.find @objects, (o) -> o instanceof clss or o instanceof TmpObject and o.object instanceof clss getOccupant: -> _.find @objects, (o) -> o.isSpaceEgoistic() diff --git a/coffee/event.coffee b/coffee/event.coffee index ddd5b74..a4bc567 100644 --- a/coffee/event.coffee +++ b/coffee/event.coffee @@ -52,6 +52,7 @@ class Event _.pull @finished_actions, action triggerActions: () -> + return if not @actions.length @time = world.getTime() log 'trigger actions', @time, @actions.length @save_actions = _.clone @actions @@ -62,16 +63,15 @@ class Event if @save_actions.length and action == last @save_actions @save_actions.pop() - addFinishedAction: (action) -> @finished_actions.push action + addFinishedAction: (action) -> + log "Event.addFinishedAction #{action.name} #{@finished_actions.length}" + @finished_actions.push action finishActions: () -> - try - while @finished_actions.length - action = last @finished_actions - action.finished() - if @finished_actions.length and action == last @finished_actions - @finished_actions.pop() - catch err - log "!!! finishActions failed !!!", err + while @finished_actions.length + action = last @finished_actions + action.finished() + if @finished_actions.length and action == last @finished_actions + @finished_actions.pop() module.exports = Event diff --git a/coffee/levels/plate.coffee b/coffee/levels/plate.coffee index 3ff5b8a..05f4d6a 100644 --- a/coffee/levels/plate.coffee +++ b/coffee/levels/plate.coffee @@ -1,7 +1,7 @@ # level design by Michael Abel -KQuaternion = require '../lib/quaternion' -KVector = require '../lib/vector' +Quaternion = require '../lib/quaternion' +Vector = require '../lib/vector' module.exports = name: "plate" @@ -16,7 +16,7 @@ module.exports = player: coordinates: [3,2,1] nostatus: 0 - orientation: KQuaternion.rotationAroundVector(270, KVector(1,0,0)) + orientation: Quaternion.rotationAroundVector(270, new Vector(1,0,0)) exits: [ name: "exit" active: 1 @@ -29,9 +29,9 @@ module.exports = world.addObjectPoly(stone, [world.decenter(1,1,0),world.decenter(1,-1,0), world.decenter(-1,-1,0),world.decenter(-1,1,0)], 1) - world.addObjectAtPos(KikiBomb(), world.decenter(0,1,-4)) - world.addObjectAtPos(KikiBomb(), world.decenter(0,-1,-4)) - world.addObjectAtPos(KikiBomb(), world.decenter(1,0,-4)) - world.addObjectAtPos(KikiBomb(), world.decenter(-1,0,-4)) + world.addObjectAtPos 'KikiBomb', world.decenter 0,1,-4 + world.addObjectAtPos 'KikiBomb', world.decenter 0,-1,-4 + world.addObjectAtPos 'KikiBomb', world.decenter 1,0,-4 + world.addObjectAtPos 'KikiBomb', world.decenter -1,0,-4 - world.addObjectAtPos(KikiBomb(), world.decenter(0,0,-2)) + world.addObjectAtPos 'KikiBomb', world.decenter 0,0,-2 diff --git a/coffee/lib/quaternion.coffee b/coffee/lib/quaternion.coffee index 0e447cc..a4c0d0d 100644 --- a/coffee/lib/quaternion.coffee +++ b/coffee/lib/quaternion.coffee @@ -59,9 +59,10 @@ class Quaternion w /= l; x = -x/l; y = -y/l; z = -z/l @ + isZero: -> @x==@y==@z==0 and @w==1 reset: -> @x=@y=@z=0 - @w=1.0 + @w=1 @ conjugate: -> diff --git a/coffee/lib/vector.coffee b/coffee/lib/vector.coffee index 754e52f..f3004af 100644 --- a/coffee/lib/vector.coffee +++ b/coffee/lib/vector.coffee @@ -5,10 +5,6 @@ # 000 000 000 000 000 000 000 000 # 0 00000000 0000000 000 0000000 000 000 -#define kMinMax(a,b,c) (kMax((a), kMin((b), (c)))) -#define kAbsMax(a,b) ((kAbs((a)) >= kAbs((b))) ? (a) : (b)) -#define kAbsMin(a,b) ((kAbs((a)) < kAbs((b))) ? (a) : (b)) - # X = 0 # SX = 0 # Y = 1 @@ -60,7 +56,10 @@ class Vector @ xyperp: -> new Vector -@y, @x - round: -> new Vector rint(@x), rint(@y), rint(@z), @w + round: -> new Vector @rint(@x), @rint(@y), @rint(@z), @w + rint: (n) -> + if n < 0 then Math.floor(n - 0.5) + else Math.round n xyangle: (v) -> thisXY = new Vector(@x, @y).normal() @@ -105,8 +104,6 @@ class Vector isZero: -> @x == @y == @z == 0 - # glTranslate: () -> glTranslatef @x,@y,@z - @DEG2RAD: (d) -> Math.PI*d/180.0 @RAD2DEG: (r) -> r*180.0/Math.PI diff --git a/coffee/player.coffee b/coffee/player.coffee index 5ede12b..4941602 100644 --- a/coffee/player.coffee +++ b/coffee/player.coffee @@ -152,8 +152,8 @@ class Player extends Bot log 'getBehindProjection' @updatePosition() - @playerDir = getCurrentDir() - @playerUp = @current_orientation.rotate(new Vector(0,1,0)).normal() + playerDir = getCurrentDir() + playerUp = @current_orientation.rotate(new Vector(0,1,0)).normal() # find a valid camera position botToCamera = (playerUp - 2 * playerDir) @@ -201,7 +201,7 @@ class Player extends Bot playerPos = @current_position # desired look pos playerDir = @getCurrentDir() - playerUp = current_orientation.rotate(new Vector(0,1,0)).normal() + playerUp = @current_orientation.rotate new Vector(0,1,0).normal() playerRight = playerDir.cross(playerUp).normal() # ____________________________________________________ camera follows bot @@ -229,7 +229,7 @@ class Player extends Bot # if camera below bot, rotate up if botToCameraNormal.dot(playerUp) < 0 # calculate angle between player to camera vector and player up vector - verticalAngle = Vector.RAD2DEG Math.acos(kMinMax(-1.0, 1.0, botToCameraNormal.dot playerUp)) - 90.0 + verticalAngle = Vector.RAD2DEG Math.acos(clamp(-1.0, 1.0, botToCameraNormal.dot playerUp)) - 90.0 cameraPos = playerPos.plus Quaternion.rotationAroundVector(verticalAngle/40.0, botToCameraNormal.cross(playerUp)).rotate botToCamera botToCamera = cameraPos.minus playerPos @@ -249,7 +249,7 @@ class Player extends Bot # ____________________________________________________ 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(kMinMax(-1.0, 1.0, -playerDir.dot mappedToXZ)) + horizontalAngle = Vector.RAD2DEG Math.acos(clamp(-1.0, 1.0, -playerDir.dot mappedToXZ)) if botToCameraNormal.dot(playerRight) > 0 horizontalAngle = -horizontalAngle @@ -273,7 +273,7 @@ class Player extends Bot # slowly adjust up vector by interpolating current and desired up vectors upDelta = 2.0 - @projection.getYVector().dot playerUp upDelta *= upDelta / 100.0 - KVector newRightVector = (@projection.getYVector().mul(1.0 - upDelta).plus playerUp.mul(upDelta)).cross newLookVector + newRightVector = (@projection.getYVector().mul(1.0-upDelta).plus playerUp.mul(upDelta)).cross newLookVector newRightVector.normalize() newUpVector = newLookVector.cross(newRightVector).normal() @@ -281,10 +281,8 @@ class Player extends Bot @projection.setZVector newLookVector @projection.setXVector newRightVector @projection.setYVector newUpVector - @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 @@ -306,9 +304,9 @@ class Player extends Bot super action finishRotateAction: () -> - if rotate_action + if @rotate_action @rotate = false - @finishAction rotate_action + @finishAction @rotate_action # 00000000 00000000 00000000 00000000 0000000 00000000 00 00 # 000 000 000 000 000 000 000 000 000 000 000 000 @@ -356,10 +354,10 @@ class Player extends Bot super action if actionId == Action.TURN_LEFT or actionId == Action.TURN_RIGHT - if rotate - @rotate_action = @getActionWithId rotate - rotate_action.reset() - Timer.addAction rotate_action + if @rotate + @rotate_action = @getActionWithId @rotate + @rotate_action.reset() + Timer.addAction @rotate_action die: () -> # Controller.removeKeyHandler @ @@ -419,11 +417,11 @@ class Player extends Bot return keyHandled() - if combo == @key.turn or combo == @key.right - rotate = (combo == @key.left) and Action.TURN_LEFT or Action.TURN_RIGHT + if combo == @key.left or combo == @key.right + @rotate = (combo == @key.left) and Action.TURN_LEFT or Action.TURN_RIGHT if @rotate_action == null and not @spiked # player is not performing a rotation and unspiked - @rotate_action = @getActionWithId rotate + @rotate_action = @getActionWithId @rotate Timer.addAction @rotate_action return keyHandled() @@ -488,11 +486,11 @@ class Player extends Bot return releaseHandled() if combo == @key.left or combo == @key.right - rotate = 0 + @rotate = 0 return releaseHandled() if key.name == @key.push - push = false + @push = false return releaseHandled() if combo == @key.lookDown or combo == @key.lookUp diff --git a/coffee/timer.coffee b/coffee/timer.coffee index 07a9b00..b08de0a 100644 --- a/coffee/timer.coffee +++ b/coffee/timer.coffee @@ -21,11 +21,11 @@ class Timer @event.removeActionsOfObject o @addAction: (a) -> - log "addAction" + log "addAction #{a.name}" @event.addAction a @removeAction: (a) -> - log "removeAction" + log "removeAction #{a.name}" @event.removeAction a module.exports = Timer diff --git a/coffee/world.coffee b/coffee/world.coffee index ecb4af7..e1d2082 100644 --- a/coffee/world.coffee +++ b/coffee/world.coffee @@ -5,6 +5,8 @@ # 000 000 000 000 000 000 000 000 000 # 00 00 0000000 000 000 0000000 0000000 { +absMin, +clamp, first, last} = require "/Users/kodi/s/ko/js/tools/tools" log = require "/Users/kodi/s/ko/js/tools/log" @@ -38,6 +40,8 @@ class World extends Actor super + @speed = 5 + @screenSize = new Size @view.clientWidth, @view.clientHeight # log "view @screenSize:", @screenSize @@ -743,8 +747,13 @@ class World extends Actor getTime: -> now().toFixed 0 setSpeed: (s) -> @speed = s getSpeed: -> @speed - mapMsTime: (unmapped) -> parseInt 10.0 * unmapped/@speed - unmapMsTime: (mapped) -> parseInt mapped * @speed/10.0 + mapMsTime: (unmapped) -> + # log "mapMsTime #{unmapped} #{@speed} #{parseInt 10.0 * unmapped/@speed}" + parseInt 10.0 * unmapped/@speed + unmapMsTime: (mapped) -> + # log "unmapMsTime #{mapped} #{@speed} #{parseInt mapped * @speed/10.0}" + parseInt mapped * @speed/10.0 + getRelativeTime: -> @frame_time % (10000/@speed)/(10000.0/@speed) getRelativeDelta: -> (@frame_time - @last_time)/(10000.0/@speed) @@ -773,6 +782,7 @@ class World extends Actor Math.min(size.z-1, Math.max(pos.z, 0)) isUnoccupiedPos: (pos) -> + log 'world.isUnoccupiedPos', pos return false if @isInvalidPos pos not @getOccupantAtPos pos @@ -837,7 +847,7 @@ class World extends Actor f = kRayPlaneIntersectionFactor pos, -@normals[w], planePos, @normals[w] - min_f = kAbsMin min_f, f + min_f = absMin min_f, f min_f # returns the distace to the next wall in direction rayDirection from rayPos (positive values only)