This commit is contained in:
monsterkodi 2016-08-13 15:20:23 +02:00
parent fcd0407cd0
commit 1ce6de6d7e
8 changed files with 225 additions and 175 deletions

View File

@ -4,7 +4,8 @@
# 000 000 000 000 000 000 000 000 0000 # 000 000 000 000 000 000 000 000 0000
# 000 000 0000000 000 000 0000000 000 000 # 000 000 0000000 000 000 0000000 000 000
_ = require 'lodash' log = require '/Users/kodi/s/ko/js/tools/log'
_ = require 'lodash'
class Action class Action
@ -21,6 +22,9 @@ class Action
@FALL_FORWARD = 10 @FALL_FORWARD = 10
@SHOOT = 11 @SHOOT = 11
@END = 12 @END = 12
@LOOK_UP = 13
@LOOK_DOWN = 14
@LOOK_RESET = 15
@ONCE = 0 @ONCE = 0
@CONTINUOUS = 1 @CONTINUOUS = 1
@ -28,11 +32,16 @@ class Action
constructor: (o, i, n, d, m) -> constructor: (o, i, n, d, m) ->
if _.isPlainObject o if _.isPlainObject o
i = o.id ? 0 i = o.id ? -1
n = o.name n = o.name
d = o.duration ? 0 d = o.duration ? 0
m = o.mode ? Action.ONCE m = o.mode ? Action.ONCE
o = o.func o = o.func
else
i ?= -1
m ?= Action.ONCE
d ?= 0
log "newAction #{i} #{n} #{d} #{m}"
@object = o @object = o
@name = n @name = n
@id = i @id = i
@ -87,11 +96,9 @@ class Action
@current = @rest @current = @rest
@rest = 0 @rest = 0
getRelativeTime: () -> getRelativeTime: -> @current / @getDuration()
return @current / @getDuration() getRelativeDelta: -> (@current-@last) / @getDuration()
getDuration: -> world.mapMsTime @duration
getDuration: () ->
return world.mapMsTime @duration
performWithEvent: (event) -> performWithEvent: (event) ->
eventTime = event.getTime() eventTime = event.getTime()
@ -101,15 +108,11 @@ class Action
@current = 0 @current = 0
@rest = 0 @rest = 0
@last = 0 @last = 0
if @duration == 0 and @mode == Action.ONCE event.removeAction @ if @duration == 0 and @mode == Action.ONCE
event.removeAction @
@perform() @perform()
@last = @current @last = @current
@finished() if @duration == 0 and @mode == Action.ONCE
if @duration == 0 and @mode == Action.ONCE
@finished()
else else
currentDiff = eventTime - @start currentDiff = eventTime - @start
if currentDiff >= @getDuration() if currentDiff >= @getDuration()
@ -123,8 +126,7 @@ class Action
if @mode == Action.CONTINUOUS if @mode == Action.CONTINUOUS
@current = @rest @current = @rest
return return
if @mode == Action.ONCE event.removeAction @ if @mode == Action.ONCE
event.removeAction @
@finish() @finish()

View File

@ -9,6 +9,7 @@ last
} = require '/Users/kodi/s/ko/js/tools/tools' } = require '/Users/kodi/s/ko/js/tools/tools'
log = require '/Users/kodi/s/ko/js/tools/log' log = require '/Users/kodi/s/ko/js/tools/log'
Action = require './action' Action = require './action'
Timer = require './timer'
Event = require './event' Event = require './event'
Emitter = require 'events' Emitter = require 'events'
_ = require 'lodash' _ = require 'lodash'
@ -20,46 +21,11 @@ class Actor extends Emitter
@events = [] @events = []
super super
addAction: (action) -> # 00000000 000 000 00000000 000 000 000000000
@actions.push action if not _.find @actions, action # 000 000 000 000 0000 000 000
# 0000000 000 000 0000000 000 0 000 000
del: -> @deleteActions() # 000 000 000 000 0000 000
# 00000000 0 00000000 000 000 000
deleteActions: ->
last(@actions).del() while @actions.length
initAction: ->
performAction: ->
finishAction: ->
actionFinished: ->
stopAction: (action) ->
# Controller.timer_event.removeAction action
startTimer: (duration, mode) ->
action = new Action @, 0, "timer", duration, mode
@actions.push action
# Controller.timer_event.addAction action
startTimedAction: (action, duration) ->
action.duration = duration if duration >= 0
# Controller.timer_event.addAction action
removeAction: (action) ->
_.pull @actions, action
getActionWithId: (actionId) ->
if actionId < @actions.length and @actions[actionId].id == actionId
return @actions[actionId]
# to be deleted...
log "[WARNING] Actor.getActionWithId #{actionId} [#{@actions.length}]"
for a in @actions
return a if a.id == actionId
getActionWithName: (name) ->
for a in @actions
return a if action.name = name
addEventWithName: (eventName) -> addEventWithName: (eventName) ->
log "Actor.addEventWithName eventName:#{eventName}" log "Actor.addEventWithName eventName:#{eventName}"
@ -76,4 +42,53 @@ class Actor extends Emitter
getEventWithId: (eventId) -> getEventWithId: (eventId) ->
return @events[eventId] return @events[eventId]
# 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
# 000 000 000 000 000 000 000 000 0000
# 000 000 0000000 000 000 0000000 000 000
addAction: (action) -> @actions[action.id] = action
del: -> @deleteActions()
deleteActions: -> last(@actions).del() while @actions.length
removeAction: (action) -> _.pull @actions, action
getActionWithId: (actionId) ->
if actionId < @actions.length and @actions[actionId].id == actionId
return @actions[actionId]
# to be deleted...
log "[WARNING] Actor.getActionWithId #{actionId} [#{@actions.length}]", (a.id for a in @actions)
for a in @actions
return a if a.id == actionId
getActionWithName: (name) ->
for a in @actions
return a if action.name = name
initAction: ->
performAction: ->
finishAction: ->
actionFinished: ->
# 000000000 000 00 00 00000000 00000000
# 000 000 000 000 000 000 000
# 000 000 000000000 0000000 0000000
# 000 000 000 0 000 000 000 000
# 000 000 000 000 00000000 000 000
stopAction: (action) -> Timer.removeAction action
startTimer: (duration, mode) ->
action = new Action @, 0, "timer", duration, mode
@actions.push action
Timer.addAction action
startTimedAction: (action, duration) ->
action.duration = duration if duration >= 0
Timer.addAction action
module.exports = Actor module.exports = Actor

View File

@ -8,6 +8,7 @@ log = require '/Users/kodi/s/ko/js/tools/log'
Pushable = require './pushable' Pushable = require './pushable'
Action = require './action' Action = require './action'
Timer = require './timer' Timer = require './timer'
Pos = require './lib/pos'
Vector = require './lib/vector' Vector = require './lib/vector'
Quaternion = require './lib/quaternion' Quaternion = require './lib/quaternion'
@ -35,7 +36,6 @@ class Bot extends Pushable
@mesh = new THREE.Mesh @geom, @mat @mesh = new THREE.Mesh @geom, @mat
world.scene.add @mesh world.scene.add @mesh
# @mesh.matrixAutoUpdate = true
@left_tire_rot = 0.0 @left_tire_rot = 0.0
@right_tire_rot = 0.0 @right_tire_rot = 0.0
@ -113,7 +113,8 @@ class Bot extends Pushable
isFalling: -> @move_action and @move_action.id == Action.FALL isFalling: -> @move_action and @move_action.id == Action.FALL
initAction: (action) -> initAction: (action) ->
newPos = new KikiPos @position log "initAction #{action.name}"
newPos = new Pos @position
switch action.id switch action.id
when Action.NOOP then return when Action.NOOP then return
@ -134,14 +135,16 @@ class Bot extends Pushable
super action super action
return return
# if newPos != @position if newPos != @position
# world.objectWillMoveToPos (@, newPos, action.getDuration()) world.objectWillMoveToPos @, newPos, action.getDuration()
performAction: (action) -> performAction: (action) ->
actionId = action.id actionId = action.id
relTime = action.getRelativeTime() relTime = action.getRelativeTime()
dltTime = action.getRelativeDelta() dltTime = action.getRelativeDelta()
log "performAction #{action.name} #{relTime} #{dltTime} id #{actionId}"
switch actionId switch actionId
when Action.SHOOT when Action.SHOOT
if relTime == 0 if relTime == 0
@ -151,27 +154,27 @@ class Bot extends Pushable
when Action.FORWARD when Action.FORWARD
@left_tire_rot += dir_sgn * dltTime @left_tire_rot += @dir_sgn * dltTime
@right_tire_rot += dir_sgn * dltTime @right_tire_rot += @dir_sgn * dltTime
@current_position = @position + relTime * @getDir() @current_position = @position.plus @getDir().mul relTime
log 'forward', @current_position
return return
when Action.JUMP when Action.JUMP
@current_position = @position + Math.cos(Math.PI/2 - Math.PI/2 * relTime) * @getUp() @current_position = @position.plus @getUp().mul Math.cos(Math.PI/2 - Math.PI/2 * relTime)
return return
when Action.JUMP_FORWARD when Action.JUMP_FORWARD
@left_tire_rot += Math.cos(Math.PI/2 - Math.PI/2 * dltTime) @left_tire_rot += Math.cos(Math.PI/2 - Math.PI/2 * dltTime)
@right_tire_rot += Math.cos(Math.PI/2 - Math.PI/2 * dltTime) @right_tire_rot += Math.cos(Math.PI/2 - Math.PI/2 * dltTime)
@current_position = @position + (1.0 - Math.cos(Math.PI/2 * relTime)) * @getDir() + Math.cos(Math.PI/2 - Math.PI/2 * relTime) * @getUp() @current_position = @position.plus @getDir().mul(1.0 - Math.cos(Math.PI/2 * relTime)).plus @getUp().mul Math.cos(Math.PI/2 - Math.PI/2 * relTime)
return return
when Action.FALL_FORWARD when Action.FALL_FORWARD
@current_position = @position + Math.cos(Math.PI/2 - Math.PI/2 * relTime) * @getDir() + (1.0 - Math.cos(Math.PI/2 * relTime)) * @getDown() @current_position = @position.plus @getDir().mul(Math.cos(Math.PI/2 - Math.PI/2 * relTime)).plus @getDown().mul (1.0 - Math.cos(Math.PI/2 * relTime))
return return
when Action.FALL when Action.FALL
@ -179,28 +182,28 @@ class Bot extends Pushable
if not @direction.isZero() if not @direction.isZero()
super action super action
return return
@current_position = @position + relTime * @getDown() @current_position = @position.plus @getDown().mul relTime
return return
when Action.CLIMB_UP when Action.CLIMB_UP
@left_tire_rot += dir_sgn * dltTime/2 @left_tire_rot += @dir_sgn * dltTime/2
@right_tire_rot += dir_sgn * dltTime/2 @right_tire_rot += @dir_sgn * dltTime/2
@climb_orientation = Quaternion.rotationAroundVector(dir_sgn * relTime * -90.0, KVector(1,0,0)) @climb_orientation = Quaternion.rotationAroundVector @dir_sgn * relTime * -90.0, new Vector(1,0,0)
break break
when Action.CLIMB_DOWN when Action.CLIMB_DOWN
@left_tire_rot += dir_sgn * dltTime @left_tire_rot += @dir_sgn * dltTime
@right_tire_rot += dir_sgn * dltTime @right_tire_rot += @dir_sgn * dltTime
if relTime <= 0.2 if relTime <= 0.2
@current_position = @position + (relTime/0.2)/2 * @getDir() @current_position = @position.plus @getDir().mul (relTime/0.2)/2
else if (relTime >= 0.8) else if (relTime >= 0.8)
@climb_orientation = Quaternion.rotationAroundVector(dir_sgn * 90.0, KVector(1,0,0)) @climb_orientation = Quaternion.rotationAroundVector @dir_sgn * 90.0, new Vector 1,0,0
@current_position = @position + @getDir() + (0.5+(relTime-0.8)/0.2/2) * @getDown() @current_position = @position.plus @getDir().plus @getDown().mul 0.5+(relTime-0.8)/0.2/2
else else
@climb_orientation = Quaternion.rotationAroundVector(dir_sgn * (relTime-0.2)/0.6 * 90.0, KVector(1,0,0)) @climb_orientation = Quaternion.rotationAroundVector @dir_sgn * (relTime-0.2)/0.6 * 90.0, new Vector 1,0,0
rotVec = (orientation * @climb_orientation).rotate(KVector(0.0, 1.0, 0.0)) rotVec = (orientation.mul @climb_orientation).rotate new Vector 0,1,0
@current_position = @position.plus @getDir().plus(@getDown()).plus(rotVec).mul 0.5 @current_position = @position.plus @getDir().plus(@getDown()).plus(rotVec).mul 0.5
break break
@ -209,20 +212,20 @@ class Bot extends Pushable
if @move_action == null and relTime == 0.0 # if not performing move action and start of rotation 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 # update @orientation now, so next move action will move in desired @direction
if actionId == Action.TURN_LEFT if actionId == Action.TURN_LEFT
@orientation *= Quaternion.rotationAroundVector(90.0, KVector(0,1,0)) @orientation *= Quaternion.rotationAroundVector 90.0, new Vector 0,1,0
@rest_orientation = Quaternion.rotationAroundVector(-90.0, KVector(0,1,0)) @rest_orientation = Quaternion.rotationAroundVector -90.0, new Vector 0,1,0
else else
@orientation *= Quaternion.rotationAroundVector(-90.0, KVector(0,1,0)) @orientation *= Quaternion.rotationAroundVector -90.0, new Vector 0,1,0
@rest_orientation = Quaternion.rotationAroundVector(90.0, KVector(0,1,0)) @rest_orientation = Quaternion.rotationAroundVector 90.0, new Vector 0,1,0
if actionId == Action.TURN_LEFT if actionId == Action.TURN_LEFT
@left_tire_rot += -dltTime @left_tire_rot += -dltTime
@right_tire_rot += dltTime @right_tire_rot += dltTime
@rotate_orientation = Quaternion.rotationAroundVector(relTime * 90.0, KVector(0,1,0)) @rotate_orientation = Quaternion.rotationAroundVector relTime * 90.0, new Vector 0,1,0
else else
@left_tire_rot += dltTime @left_tire_rot += dltTime
@right_tire_rot += -dltTime @right_tire_rot += -dltTime
@rotate_orientation = Quaternion.rotationAroundVector(relTime * -90.0, KVector(0,1,0)) @rotate_orientation = Quaternion.rotationAroundVector relTime * -90.0, new Vector 0,1,0
break break
else else
@ -230,8 +233,7 @@ class Bot extends Pushable
super action super action
return return
@current_orientation = @orientation * @climb_orientation * @rotate_orientation * @rest_orientation @current_orientation = @orientation.mul @climb_orientation.mul @rotate_orientation.mul @rest_orientation
finishAction: (action) -> finishAction: (action) ->
actionId = action.id actionId = action.id
@ -246,33 +248,33 @@ class Bot extends Pushable
@rotate_action = null @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 *= @rotate_orientation @rest_orientation = @rest_orientation.mul @rotate_orientation
@rotate_orientation.reset() @rotate_orientation.reset()
else else
@orientation *= @rotate_orientation * @rest_orientation # update rotation matrix @orientation = @orientation.mul @rotate_orientation.mul @rest_orientation # update rotation matrix
@rotate_orientation.reset() @rotate_orientation.reset()
@rest_orientation.reset() @rest_orientation.reset()
else if actionId < Action.END else if actionId < Action.END
@move_action = null @move_action = null
@orientation *= @climb_orientation # update climb @orientation @orientation = @orientation.mul @climb_orientation # update climb @orientation
@climb_orientation.reset() @climb_orientation.reset()
if @rotate_action and actionId != Action.JUMP_FORWARD # bot is currently performing a rotation -> if @rotate_action and actionId != Action.JUMP_FORWARD # bot is currently performing a rotation ->
# take over result of rotation to prevent sliding # take over result of rotation to prevent sliding
if @rotate_action.id == Action.TURN_LEFT if @rotate_action.id == Action.TURN_LEFT
@orientation *= Quaternion.rotationAroundVector(90.0, KVector(0,1,0)) * @rest_orientation @orientation = @orientation.mul Quaternion.rotationAroundVector(90.0, new Vector(0,1,0)).mul @rest_orientation
@rest_orientation = Quaternion.rotationAroundVector(-90.0, KVector(0,1,0)) @rest_orientation = Quaternion.rotationAroundVector -90.0, new Vector 0,1,0
else else
@orientation *= Quaternion.rotationAroundVector(-90.0, KVector(0,1,0)) * @rest_orientation @orientation = @orientation.mul Quaternion.rotationAroundVector(-90.0, new Vector(0,1,0)).mul @rest_orientation
@rest_orientation = Quaternion.rotationAroundVector(90.0, KVector(0,1,0)) @rest_orientation = Quaternion.rotationAroundVector 90.0, new Vector 0,1,0
if actionId != Action.CLIMB_UP if actionId != Action.CLIMB_UP
world.objectMovedFromPos @, @position # update world @position world.objectMovedFromPos @, @position # update world @position
@position = @current_position.round() @position = @current_position.round()
if actionId != Action.JUMP_FORWARD and @rotate_action == null # if not jumping forward if actionId != Action.JUMP_FORWARD and @rotate_action == null # if not jumping forward
@orientation *= @rest_orientation # update rotation @orientation @orientation = @orientation.mul @rest_orientation # update rotation @orientation
@rest_orientation.reset() @rest_orientation.reset()
actionFinished: (action) -> actionFinished: (action) ->
@ -285,7 +287,7 @@ class Bot extends Pushable
# dead player may only fall, nothing else # dead player may only fall, nothing else
return return
if spiked if @spiked
@move_action = null @move_action = null
@startTimedAction getActionWithId(Action.NOOP), 0 @startTimedAction getActionWithId(Action.NOOP), 0
return return
@ -308,22 +310,22 @@ class Bot extends Pushable
@move_action.takeRest (action) @move_action.takeRest (action)
else else
@move_action = @getActionWithId Action.FORWARD @move_action = @getActionWithId Action.FORWARD
playSoundAtPos(KikiSound.BOT_LAND, @getPos(), 0.25) world.playSound 'BOT_LAND', @getPos(), 0.25
else # forward will not be empty 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 @move_action = @getActionWithId Action.CLIMB_UP
playSoundAtPos KikiSound.BOT_LAND, @getPos(), 0.5 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 move # sticky if moving
if world.isUnoccupiedPos position.plus @getDir() if world.isUnoccupiedPos position.plus @getDir()
# forward will be empty # forward will be empty
if world.isOccupiedPos position.plus @getDir().minus @getUp() if world.isOccupiedPos position.plus @getDir().minus @getUp()
# below forward is solid # below forward is solid
KikiObject * occupant = world.getOccupantAtPos position.plus @getDir().minus @getUp() occupant = world.getOccupantAtPos position.plus @getDir().minus @getUp()
if occupant == null or not occupant.isSlippery() if occupant == null or not occupant.isSlippery()
@move_action = @getActionWithId (Action.FORWARD) @move_action = @getActionWithId (Action.FORWARD)
else else
KikiObject * occupant = world.getOccupantAtPos position.plus @getDir() occupant = world.getOccupantAtPos position.plus @getDir()
if occupant == null or not occupant.isSlippery() if occupant == null or not occupant.isSlippery()
@move_action = @getActionWithId (Action.CLIMB_UP) @move_action = @getActionWithId (Action.CLIMB_UP)
@ -331,10 +333,10 @@ class Bot extends Pushable
@move_action = @getActionWithId Action.FALL @move_action = @getActionWithId Action.FALL
@move_action.takeRest action @move_action.takeRest action
else if actionId == Action.FALL or actionId == Action.FALL_FORWARD # landed else if actionId == Action.FALL or actionId == Action.FALL_FORWARD # landed
if @ == player if @ == world.player
playSound KikiSound.BOT_LAND world.playSound 'BOT_LAND'
else else
playSoundAtPos KikiSound.BOT_LAND, @getPos() world.playSound 'BOT_LAND', @getPos()
if @move_action if @move_action
Timer.addAction @move_action Timer.addAction @move_action
@ -345,8 +347,8 @@ class Bot extends Pushable
if @move if @move
@moveBot() @moveBot()
else else
dir_sgn = 1.0 @dir_sgn = 1.0
if actionId != Action.NOOP then jump_once = false if actionId != Action.NOOP then @jump_once = false
# keep action chain flowing in order to detect environment changes # keep action chain flowing in order to detect environment changes
@startTimedAction @getActionWithId(Action.NOOP), 0 @startTimedAction @getActionWithId(Action.NOOP), 0

View File

@ -12,28 +12,30 @@ _ = require 'lodash'
class Event class Event
constructor: (obj, name) -> constructor: (obj, name) ->
@object = obj @object = obj
@name = name @name = name
@time = 0
@actions = []
@save_actions = [] @save_actions = []
@finished_actions = []
getTime: -> @time
hasAction: (action) -> _.find @actions, action hasAction: (action) -> _.find @actions, action
addAction: (action) -> addAction: (action) ->
if @hasAction action log "Event.addAction #{action.name}"
actions.push action if action? and not @hasAction action
@actions.push action
action.event = @ action.event = @
action.init() action.init()
else
log 'no action?', action
removeAllActions: () -> removeAllActions: () ->
while actions.length while @actions.length
@removeAction last @actions @removeAction last @actions
getActionsOfObject: (object) -> getActionsOfObject: (object) -> @actions.filter (a) -> a.object == object
actions = []
for a in _.clone @actions
if a.object == object
actions.push a
actions
removeActionsOfObject: (object) -> removeActionsOfObject: (object) ->
for a in @actions for a in @actions
@ -41,8 +43,7 @@ class Event
removeActionWithName: (actionName) -> removeActionWithName: (actionName) ->
for a in @actions for a in @actions
if a.name == actionName @removeAction a if a.name == actionName
@removeAction a
removeAction: (action) -> removeAction: (action) ->
action.event = null action.event = null
@ -51,10 +52,12 @@ class Event
_.pull @finished_actions, action _.pull @finished_actions, action
triggerActions: () -> triggerActions: () ->
time = KEventHandler.getTime() @time = world.getTime()
@save_actions = KikiActionList (actions) log 'trigger actions', @time, @actions.length
@save_actions = _.clone @actions
while @save_actions.length while @save_actions.length
action= last @save_actions action = last @save_actions
log "performAction #{action.name}"
action.performWithEvent @ action.performWithEvent @
if @save_actions.length and action == last @save_actions if @save_actions.length and action == last @save_actions
@save_actions.pop() @save_actions.pop()

View File

@ -292,15 +292,16 @@ class Player extends Bot
# 000 000 0000000 000 000 0000000 000 000 # 000 000 0000000 000 000 0000000 000 000
initAction: (action) -> initAction: (action) ->
log "initAction #{action.id} #{action.name}"
actionId = action.id actionId = action.id
switch actionId switch actionId
when Action.CLIMB_DOWN, Action.FORWARD when Action.CLIMB_DOWN, Action.FORWARD
@status.addMoves 1 @status.addMoves 1
when Action.TURN_LEFT, Action.TURN_RIGHT when Action.TURN_LEFT, Action.TURN_RIGHT
sound.playSound KikiSound.BOT_MOVE world.playSound 'BOT_MOVE'
when Action.JUMP, Action.JUMP_FORWARD when Action.JUMP, Action.JUMP_FORWARD
@status.addMoves actionId == Action.JUMP and 1 or 2 @status.addMoves actionId == Action.JUMP and 1 or 2
sound.playSound KikiSound.BOT_JUMP world.playSound 'BOT_JUMP'
super action super action
@ -352,11 +353,11 @@ class Player extends Bot
@dir_sgn = @new_dir_sgn @dir_sgn = @new_dir_sgn
if actionId != Action.LOOK_UP and actionId != Action.LOOK_DOWN if actionId != Action.LOOK_UP and actionId != Action.LOOK_DOWN
KikiBot.finishAction(action) super action
if actionId == Action.TURN_LEFT or actionId == Action.TURN_RIGHT if actionId == Action.TURN_LEFT or actionId == Action.TURN_RIGHT
if rotate if rotate
@rotate_action = getActionWithId rotate @rotate_action = @getActionWithId rotate
rotate_action.reset() rotate_action.reset()
Timer.addAction rotate_action Timer.addAction rotate_action
@ -364,7 +365,7 @@ class Player extends Bot
# Controller.removeKeyHandler @ # Controller.removeKeyHandler @
super super
# Controller.displayText "game over" # Controller.displayText "game over"
# sound.playSound KikiSound.BOT_DEATH world.playSound 'BOT_DEATH'
world.setCameraMode world.CAMERA_FOLLOW world.setCameraMode world.CAMERA_FOLLOW
reborn: () -> reborn: () ->
@ -421,8 +422,8 @@ class Player extends Bot
if combo == @key.turn or combo == @key.right if combo == @key.turn or combo == @key.right
rotate = (combo == @key.left) and Action.TURN_LEFT or Action.TURN_RIGHT rotate = (combo == @key.left) and Action.TURN_LEFT or Action.TURN_RIGHT
if @rotate_action == null and spiked == false # player is not performing a rotation and unspiked 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 Timer.addAction @rotate_action
return keyHandled() return keyHandled()
@ -481,8 +482,8 @@ class Player extends Bot
if jump_once if jump_once
if @move_action == null and world.isUnoccupiedPos position.plus @getUp() if @move_action == null and world.isUnoccupiedPos position.plus @getUp()
jump_once = false jump_once = false
@move_action = getActionWithId Action.JUMP @move_action = @getActionWithId Action.JUMP
sound.playSound KikiSound.BOT_JUMP world.playSound 'BOT_JUMP'
Timer.addAction @move_action Timer.addAction @move_action
return releaseHandled() return releaseHandled()
@ -497,7 +498,7 @@ class Player extends Bot
if combo == @key.lookDown or combo == @key.lookUp if combo == @key.lookDown or combo == @key.lookUp
if @look_action and @look_action.id != Action.LOOK_RESET if @look_action and @look_action.id != Action.LOOK_RESET
Timer.removeAction @look_action Timer.removeAction @look_action
@look_action = getActionWithId Action.LOOK_RESET @look_action = @getActionWithId Action.LOOK_RESET
Timer.addAction @look_action Timer.addAction @look_action
return releaseHandled() return releaseHandled()

View File

@ -26,13 +26,13 @@ class Pushable extends Item
@move_action = pushAction @move_action = pushAction
@direction = dir @direction = dir
# pushAction->setDuration Controller.unmapMsTime duration pushAction.setDuration world.unmapMsTime duration
# Controller.timer_event->addAction (pushAction); Timer.addAction pushAction
initAction: (action) -> initAction: (action) ->
# switch action->getId() switch action.id
# when Action.FALL when Action.FALL
# Controller.world->objectWillMoveToPos @, @position + @direction, action->getDuration() world.objectWillMoveToPos @, @position.plus(@direction), action.getDuration()
performAction: (action) -> performAction: (action) ->
switch action.id switch action.id
@ -53,10 +53,10 @@ class Pushable extends Item
gravityDir = @direction gravityDir = @direction
if actionId == Action.PUSH if actionId == Action.PUSH
if @pusher instanceof KikiBot if @pusher instanceof Bot
gravityDir = pusher.getDown() gravityDir = pusher.getDown()
else if pusher instanceof KikiBomb else if pusher instanceof Bomb
if @ instanceof KikiBot if @ instanceof Bot
if @direction == @getUp() if @direction == @getUp()
# bots don't fall through bomb splitter # bots don't fall through bomb splitter
@direction.reset() @direction.reset()
@ -70,9 +70,9 @@ class Pushable extends Item
if world.isUnoccupiedPos @position + gravityDir if world.isUnoccupiedPos @position + gravityDir
@direction = gravityDir @direction = gravityDir
@move_action = @getActionWithId Action.FALL @move_action = @getActionWithId Action.FALL
# Controller.timer_event->addAction (move_action) Timer.addAction @move_action
else else
@direction.reset() @direction.reset()
# playSoundAtPos landing_sound, position world.playSound @landing_sound, position
module.exports = Pushable module.exports = Pushable

View File

@ -8,8 +8,24 @@ log = require '/Users/kodi/s/ko/js/tools/log'
class Timer class Timer
@removeActionsOfObject: (o) -> log "removeActionsOfObject" @event = null
@addAction: (a) -> log "addAction" @eventID = -1
@removeAction: (a) -> log "removeAction"
@init: ->
@eventID = world.addEventWithName 'timer'
@event = world.getEventWithId @eventID
log "Timer.@init @eventID:#{@eventID} #{@event.name}"
@removeActionsOfObject: (o) ->
log "removeActionsOfObject"
@event.removeActionsOfObject o
@addAction: (a) ->
log "addAction"
@event.addAction a
@removeAction: (a) ->
log "removeAction"
@event.removeAction a
module.exports = Timer module.exports = Timer

View File

@ -14,15 +14,17 @@ Cell = require './cell'
Light = require './light' Light = require './light'
Player = require './player' Player = require './player'
Timer = require './timer' Timer = require './timer'
Actor = require './actor'
TmpObject = require './tmpobject' TmpObject = require './tmpobject'
Quaternion = require './lib/quaternion' Quaternion = require './lib/quaternion'
Vector = require './lib/vector' Vector = require './lib/vector'
Pos = require './lib/pos' Pos = require './lib/pos'
_ = require 'lodash' _ = require 'lodash'
now = require 'performance-now'
world = null world = null
class World class World extends Actor
@CAMERA_INSIDE = 0 @CAMERA_INSIDE = 0
@CAMERA_BEHIND = 1 @CAMERA_BEHIND = 1
@ -30,11 +32,14 @@ class World
@levelList = [] @levelList = []
@levelDict = [] @levelDict = []
@speed = 5
constructor: (@view) -> constructor: (@view) ->
super
@screenSize = new Size @view.clientWidth, @view.clientHeight @screenSize = new Size @view.clientWidth, @view.clientHeight
log "view @screenSize:", @screenSize # log "view @screenSize:", @screenSize
@renderer = new THREE.WebGLRenderer @renderer = new THREE.WebGLRenderer
antialias: true antialias: true
@ -181,6 +186,7 @@ class World
log "create world in view:", view log "create world in view:", view
world = new World view world = new World view
global.world = world global.world = world
Timer.init()
world.create first @levelList world.create first @levelList
world world
@ -192,7 +198,7 @@ class World
create: (worldDict={}) -> # creates the world from a level name or a dictionary create: (worldDict={}) -> # creates the world from a level name or a dictionary
log "world.create", worldDict # log "world.create", worldDict
if worldDict if worldDict
if _.isString worldDict if _.isString worldDict
@ -205,7 +211,8 @@ class World
# ............................................................ appearance # ............................................................ appearance
@setSize @dict["size"] @setSize @dict["size"]
log "world size set", @size # log "world size set", @size
# if "scheme" in @dict # if "scheme" in @dict
# @applyColorScheme eval(@dict["scheme"]) # @applyColorScheme eval(@dict["scheme"])
# else # else
@ -244,7 +251,7 @@ class World
log "exits" log "exits"
exit_id = 0 exit_id = 0
for entry in @dict.exits for entry in @dict.exits
exit_gate = new KikiGate entry["active"] exit_gate = new Gate entry["active"]
if "name" in entry if "name" in entry
name = entry["name"] name = entry["name"]
@ -253,7 +260,7 @@ class World
exit_gate.setName name exit_gate.setName name
exit_action = once "exit " + str(exit_id) exit_action = once "exit " + str(exit_id)
delay_action = once (a=exit_action) -> Controller.timer_event.addAction(a) delay_action = once (a=exit_action) -> Timer.addAction a
# exit_gate.getEventWithName("enter").addAction(delay_action) # exit_gate.getEventWithName("enter").addAction(delay_action)
if entry.position? if entry.position?
pos = @decenter entry.position pos = @decenter entry.position
@ -334,8 +341,9 @@ class World
world.moveObjectToPos player, world.decenter(player_dict["position"]) world.moveObjectToPos player, world.decenter(player_dict["position"])
performAction: (name, time) -> performAction: (name, time) ->
log "world.performAction #{name}"
# action callback. used to exit current world # action callback. used to exit current world
if name.find ("exit") == 0 if /exit/.test name
@finish() @finish()
@player.status.setMoves 0 @player.status.setMoves 0
if "world" in @dict["exits"][parseInt name.slice 5] if "world" in @dict["exits"][parseInt name.slice 5]
@ -344,18 +352,15 @@ class World
w.create() w.create()
else if _.isFunction w else if _.isFunction w
w() w()
else # else
exec "World().create(" + world + ")" # exec "World().create(" + world + ")"
else else
KikiPyWorld().create (levelList[world.level_index+1]) world.create levelList[world.level_index+1]
activate: (objectName) -> activate: (objectName) ->
# activates object with name objectName # activates object with name objectName
object = @getObjectWithName(objectName) object = @getObjectWithName objectName
if object.getClassName() == "KikiSwitch" object?.setActive? 1
kikiObjectToSwitch(object).setActive(1)
else if object.getClassName() == "KikiGate"
kikiObjectToGate(object).setActive(1)
decenter: (x,y,z) -> new Pos(x,y,z).plus @size.div 2 decenter: (x,y,z) -> new Pos(x,y,z).plus @size.div 2
@ -400,9 +405,9 @@ class World
# adds number objects of type at random positions to the world # adds number objects of type at random positions to the world
for i in [0...number] for i in [0...number]
if type (object) == types.StringType if type (object) == types.StringType
@setObjectRandom (eval(object)) @setObjectRandom eval object
else else
@setObjectRandom (object()) @setObjectRandom object()
setObjectRandom: (object) -> setObjectRandom: (object) ->
# adds number objects of type at random positions to the world # adds number objects of type at random positions to the world
@ -480,8 +485,8 @@ class World
exec @dict["escape"] in globals() exec @dict["escape"] in globals()
return return
menu = KikiMenu() menu = new Menu()
menu.getEventWithName ("hide").addAction (once(@resetProjection)) menu.getEventWithName("hide").addAction once @resetProjection
# if Controller.isDebugVersion() # if Controller.isDebugVersion()
# menu.addItem (Controller.getLocalizedString("next level"), once(lambda w=self: w.performAction("exit 0",0))) # menu.addItem (Controller.getLocalizedString("next level"), once(lambda w=self: w.performAction("exit 0",0)))
@ -489,12 +494,12 @@ class World
# menu.addItem (Controller.getLocalizedString("help"), once(@help)) # menu.addItem (Controller.getLocalizedString("help"), once(@help))
menu.addItem(Controller.getLocalizedString("restart"), once(@restart)) menu.addItem(Controller.getLocalizedString("restart"), once(@restart))
esc_menu_action = once (@escape) esc_menu_action = once @escape
console.out("level_index %d" % world.level_index) log "level_index #{world.level_index}"
menu.addItem(Controller.getLocalizedString("load level"), (i=world.level_index,a=esc_menu_action) -> levelSelection(i, a)) menu.addItem(Controller.getLocalizedString("load level"), (i=world.level_index,a=esc_menu_action) -> levelSelection(i, a))
menu.addItem(Controller.getLocalizedString("setup"), once(quickSetup)) menu.addItem(Controller.getLocalizedString("setup"), once @quickSetup)
menu.addItem(Controller.getLocalizedString("about"), once(display_about)) menu.addItem(Controller.getLocalizedString("about"), once @display_about)
menu.addItem(Controller.getLocalizedString("quit"), once(Controller.quit)) menu.addItem(Controller.getLocalizedString("quit"), once world.quit)
setSize: (size) -> setSize: (size) ->
@deleteAllObjects() @deleteAllObjects()
@ -559,7 +564,7 @@ class World
newObject: (object) -> newObject: (object) ->
if _.isString object if _.isString object
log "newObject:", object # log "newObject:", object
if object.startsWith 'Kiki' if object.startsWith 'Kiki'
return new (require "./#{object.slice(4).toLowerCase()}")() return new (require "./#{object.slice(4).toLowerCase()}")()
object object
@ -587,9 +592,7 @@ class World
@unsetObject object @unsetObject object
@setObjectAtPos object, pos @setObjectAtPos object, pos
world.playSound 'BOT_LAND'
# Controller.sound.playSound(KikiSound::BOT_LAND)
true true
deleteObject: (object) -> deleteObject: (object) ->
@ -649,6 +652,7 @@ class World
@moved_objects.push object @moved_objects.push object
objectWillMoveToPos: (object, pos, duration) -> objectWillMoveToPos: (object, pos, duration) ->
log "world.objectWillMoveToPos", pos
cell = @getCellAtPos pos cell = @getCellAtPos pos
if @isInvalidPos pos if @isInvalidPos pos
@ -729,14 +733,18 @@ class World
@camera.position.set(center.x,center.y,center.z+@dist).applyQuaternion quat @camera.position.set(center.x,center.y,center.z+@dist).applyQuaternion quat
@camera.quaternion.copy quat @camera.quaternion.copy quat
Timer.event.triggerActions()
Timer.event.finishActions()
@player.getProjection().apply @camera @player.getProjection().apply @camera
@sun.position.copy @camera.position @sun.position.copy @camera.position
@renderer.render @scene, @camera @renderer.render @scene, @camera
getTime: -> now().toFixed 0
setSpeed: (s) -> @speed = s setSpeed: (s) -> @speed = s
getSpeed: -> @speed getSpeed: -> @speed
mapMsTime: (unmapped) -> parseInt 10.0 * unmapped/speed mapMsTime: (unmapped) -> parseInt 10.0 * unmapped/@speed
unmapMsTime: (mapped) -> parseInt mapped * speed/10.0 unmapMsTime: (mapped) -> parseInt mapped * @speed/10.0
getRelativeTime: -> @frame_time % (10000/@speed)/(10000.0/@speed) getRelativeTime: -> @frame_time % (10000/@speed)/(10000.0/@speed)
getRelativeDelta: -> (@frame_time - @last_time)/(10000.0/@speed) getRelativeDelta: -> (@frame_time - @last_time)/(10000.0/@speed)
@ -866,6 +874,9 @@ class World
when World.CAMERA_FOLLOW then @projection = @player.getFollowProjection() when World.CAMERA_FOLLOW then @projection = @player.getFollowProjection()
@projection.apply @camera @projection.apply @camera
playSound: (sound, pos, time) ->
log "World.playSound #{sound} #{time}", pos
# 000 000 00000000 000 000 # 000 000 00000000 000 000
# 000 000 000 000 000 # 000 000 000 000 000
# 0000000 0000000 00000 # 0000000 0000000 00000