Physics chain rollback checkpoint
parent
28e24736f3
commit
015afe0459
20
arena.lua
20
arena.lua
|
@ -8,9 +8,14 @@ function Arena:init(name)
|
|||
self.effects = Group()
|
||||
self.ui = Group():no_camera()
|
||||
self.main:disable_collision_between('player', 'player')
|
||||
self.main:disable_collision_between('player', 'enemy')
|
||||
self.main:disable_collision_between('enemy', 'enemy')
|
||||
self.main:enable_trigger_between('player', 'enemy')
|
||||
|
||||
self.x1, self.y1 = gw/2 - 0.8*gw/2, gh/2 - 0.8*gh/2
|
||||
self.x2, self.y2 = gw/2 + 0.8*gw/2, gh/2 + 0.8*gh/2
|
||||
self.spawn_points = {{x = self.x1 + 32, y = self.y1 + 32}, {x = self.x1 + 32, y = self.y2 - 32}, {x = self.x2 - 32, y = self.y1 + 32}, {x = self.x2 - 32, y = self.y2 - 32}, {x = gw/2, y = gh/2}}
|
||||
self.spawn_offsets = {{x = -12, y = -12}, {x = 12, y = -12}, {x = 12, y = 12}, {x = -12, y = 12}, {x = 0, y = 0}}
|
||||
|
||||
Wall{group = self.main, vertices = math.to_rectangle_vertices(-40, -40, self.x1, gh + 40), color = bg[-1]}
|
||||
Wall{group = self.main, vertices = math.to_rectangle_vertices(self.x2, -40, gw + 40, gh + 40), color = bg[-1]}
|
||||
|
@ -18,7 +23,7 @@ function Arena:init(name)
|
|||
Wall{group = self.main, vertices = math.to_rectangle_vertices(self.x1, self.y2, self.x2, gh + 40), color = bg[-1]}
|
||||
|
||||
self.player = Unit{group = self.main, x = gw/2, y = gh/2, player = true, leader = true, character = 'vagrant'}
|
||||
-- self.player:add_follower(Unit{group = self.main, player = true, color = red[0]})
|
||||
-- self.player:add_follower(Unit{group = self.main, player = true, character = 'seeker'})
|
||||
end
|
||||
|
||||
|
||||
|
@ -32,6 +37,10 @@ function Arena:update(dt)
|
|||
self.main:update(dt*slow_amount)
|
||||
self.effects:update(dt*slow_amount)
|
||||
self.ui:update(dt*slow_amount)
|
||||
|
||||
if input.k.pressed then
|
||||
self:spawn_enemy()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
@ -40,3 +49,12 @@ function Arena:draw()
|
|||
self.effects:draw()
|
||||
self.ui:draw()
|
||||
end
|
||||
|
||||
|
||||
function Arena:spawn_enemy()
|
||||
local p = table.random(self.spawn_points)
|
||||
local o = table.random(self.spawn_offsets)
|
||||
local leader = Unit{group = self.main, x = p.x + o.x, y = p.y + o.y, enemy = true, leader = true, character = 'seeker'}
|
||||
leader:add_follower(Unit{group = self.main, x = p.x + o.x, y = p.y + o.y, enemy = true, character = 'seeker'})
|
||||
leader:add_follower(Unit{group = self.main, x = p.x + o.x, y = p.y + o.y, enemy = true, character = 'seeker'})
|
||||
end
|
||||
|
|
|
@ -452,7 +452,7 @@ end
|
|||
-- Applies a continuous amount of force to the object
|
||||
-- self:apply_force(100*math.cos(angle), 100*math.sin(angle))
|
||||
function Physics:apply_force(fx, fy, x, y)
|
||||
if self.body then self.body:applyForce(fx, fy, x, y) end
|
||||
if self.body then self.body:applyForce(fx, fy, x or self.x, y or self.y) end
|
||||
return self
|
||||
end
|
||||
|
||||
|
|
|
@ -28,11 +28,11 @@ end
|
|||
-- then you need to destroy everything that needs to be destroyed in an on_exit function and then recreate it again in the on_enter function.
|
||||
--
|
||||
-- You'd add a state to the game like this:
|
||||
-- state.add(MyState'level_1')
|
||||
-- main:add(MyState'level_1')
|
||||
-- You'd move to that state like so:
|
||||
-- state.go_to'level_1'
|
||||
-- state.go_to automatically calls on_exit for the currently active state and on_enter for the new one.
|
||||
-- You can access the currently active state with state.current.
|
||||
-- main:go_to'level_1'
|
||||
-- main:go_to automatically calls on_exit for the currently active state and on_enter for the new one.
|
||||
-- You can access the currently active state with main.current.
|
||||
State = Object:extend()
|
||||
function State:init_state(name)
|
||||
self.name = name or random:uid()
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
-- self:set_as_steerable(100, 1000)
|
||||
function Physics:set_as_steerable(max_v, max_f, max_turn_rate, turn_multiplier)
|
||||
self.steerable = true
|
||||
self.steering_enabled = true
|
||||
self.heading = Vector()
|
||||
self.side = Vector()
|
||||
self.mass = 1
|
||||
|
@ -29,14 +30,14 @@ end
|
|||
|
||||
|
||||
function Physics:steering_update(dt)
|
||||
if self.steerable then
|
||||
if self.steerable and self.steering_enabled then
|
||||
local steering_force = self:calculate_steering_force(dt):div(self.mass)
|
||||
self:apply_force(steering_force.x, steering_force.y)
|
||||
local vx, vy = self:get_velocity()
|
||||
local v = Vector(vx, vy):truncate(self.max_v)
|
||||
self:set_velocity(v.x, v.y)
|
||||
if v:length_squared() > 0.00001 then
|
||||
self.heading = self.v:clone():normalize()
|
||||
self.heading = v:clone():normalize()
|
||||
self.side = self.heading:perpendicular()
|
||||
end
|
||||
end
|
||||
|
@ -80,7 +81,8 @@ function Physics:seek_point(x, y, deceleration, weight)
|
|||
local v = d/((deceleration or 1)*0.08)
|
||||
v = math.min(v, self.max_v)
|
||||
local dvx, dvy = v*tx/d, v*ty/d
|
||||
self.seek_f:set((dvx - self.v.x)*self.turn_multiplier*(weight or 1), (dvy - self.v.y)*self.turn_multiplier*(weight or 1))
|
||||
local vx, vy = self:get_velocity()
|
||||
self.seek_f:set((dvx - vx)*self.turn_multiplier*(weight or 1), (dvy - vy)*self.turn_multiplier*(weight or 1))
|
||||
else self.seek_f:set(0, 0) end
|
||||
end
|
||||
|
||||
|
|
81
objects.lua
81
objects.lua
|
@ -7,8 +7,17 @@ function Unit:init(args)
|
|||
|
||||
if self.character == 'vagrant' then
|
||||
self.color = fg[0]
|
||||
self.visual_shape = 'triangle'
|
||||
self.visual_shape = 'rectangle'
|
||||
self.classes = {'ranger', 'warrior', 'mage'}
|
||||
elseif self.character == 'seeker' then
|
||||
self.color = red[0]
|
||||
self.visual_shape = 'capsule'
|
||||
self.classes = {'seeker'}
|
||||
if self.enemy then
|
||||
self.enemy_behavior = 'seek'
|
||||
self:calculate_stats()
|
||||
self:set_as_steerable(self.v)
|
||||
end
|
||||
end
|
||||
|
||||
self:calculate_stats()
|
||||
|
@ -49,8 +58,34 @@ function Unit:update(dt)
|
|||
else camera.r = math.lerp_angle_dt(0.005, dt, camera.r, 0) end
|
||||
end
|
||||
|
||||
if not self.player and self.leader then
|
||||
local player = main.current.player
|
||||
if self.enemy_behavior == 'seek' then
|
||||
if self.being_pushed then
|
||||
local v = math.length(self:get_velocity())
|
||||
if v < 25 then
|
||||
self.being_pushed = false
|
||||
self.steering_enabled = true
|
||||
self:set_damping(0)
|
||||
self:set_angular_damping(0)
|
||||
end
|
||||
self.r = self:get_angle()
|
||||
else
|
||||
self:seek_point(player.x, player.y)
|
||||
self:wander(25, 100, 20)
|
||||
self:rotate_towards_velocity(0.5)
|
||||
self.r = self:get_angle()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not self.leader then
|
||||
local d = math.ceil(self.v*0.1)*self.follower_index
|
||||
local ds
|
||||
if self.parent.v >= 80 and self.parent.v <= 90 then ds = 8 end
|
||||
if self.parent.v >= 20 and self.parent.v <= 30 then ds = 12 end
|
||||
if not ds then error('undefined unit distance for parent velocity: ' .. self.parent.v) end
|
||||
|
||||
local d = ds*self.follower_index
|
||||
local p = self.parent.previous_positions[d]
|
||||
if p then
|
||||
self:set_position(p.x, p.y)
|
||||
|
@ -62,12 +97,31 @@ function Unit:update(dt)
|
|||
end
|
||||
|
||||
|
||||
function Unit:on_trigger_enter(other)
|
||||
if other:is(Unit) and other.enemy then
|
||||
other:push(math.length(self:get_velocity())/3.5, self:angle_to_object(other))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function Unit:push(f, r)
|
||||
self.being_pushed = true
|
||||
self.steering_enabled = false
|
||||
self:apply_impulse(f*math.cos(r), f*math.sin(r))
|
||||
self:apply_angular_impulse(random:float(-12*math.pi, 12*math.pi))
|
||||
self:set_damping(1.5)
|
||||
self:set_angular_damping(1.5)
|
||||
end
|
||||
|
||||
|
||||
function Unit:draw()
|
||||
graphics.push(self.x, self.y, self.r, self.hfx.hit.x, self.hfx.hit.x)
|
||||
if self.visual_shape == 'triangle' then
|
||||
graphics.triangle(self.x, self.y, self.shape.w, self.shape.h, self.hfx.hit.f and fg[0] or self.color)
|
||||
elseif self.visual_shape == 'rectangle' then
|
||||
graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 2, 2, self.hfx.hit.f and fg[0] or self.color)
|
||||
elseif self.visual_shape == 'capsule' then
|
||||
graphics.rectangle(self.x, self.y, self.shape.w, 0.525*self.shape.h, 2, 2, self.hfx.hit.f and fg[0] or self.color)
|
||||
end
|
||||
graphics.pop()
|
||||
|
||||
|
@ -154,35 +208,29 @@ function Unit:calculate_stats()
|
|||
|
||||
for _, class in ipairs(self.classes) do
|
||||
if class == 'warrior' then self.class_hp_m = self.class_hp_m*1.4
|
||||
elseif class == 'ranger' then self.class_hp_m = self.class_hp_m*1
|
||||
elseif class == 'mage' then self.class_hp_m = self.class_hp_m*0.6
|
||||
elseif class == 'healer' then self.class_hp_m = self.class_hp_m*1.1
|
||||
elseif class == 'cycler' then self.class_hp_m = self.class_hp_m*0.9 end
|
||||
elseif class == 'cycler' then self.class_hp_m = self.class_hp_m*0.9
|
||||
elseif class == 'seeker' then self.class_hp_m = self.class_hp_m*0.5 end
|
||||
end
|
||||
self.max_hp = (self.base_hp + self.class_hp_a + self.buff_hp_a)*self.class_hp_m*self.buff_hp_m
|
||||
|
||||
for _, class in ipairs(self.classes) do
|
||||
if class == 'warrior' then self.class_dmg_m = self.class_dmg_m*1.1
|
||||
elseif class == 'ranger' then self.class_dmg_m = self.class_dmg_m*1.2
|
||||
elseif class == 'mage' then self.class_dmg_m = self.class_dmg_m*1.4
|
||||
elseif class == 'healer' then self.class_dmg_m = self.class_dmg_m*1
|
||||
elseif class == 'cycler' then self.class_dmg_m = self.class_dmg_m*1 end
|
||||
elseif class == 'mage' then self.class_dmg_m = self.class_dmg_m*1.4 end
|
||||
end
|
||||
self.dmg = (self.base_dmg + self.class_dmg_a + self.buff_dmg_a)*self.class_dmg_m*self.buff_dmg_m
|
||||
|
||||
for _, class in ipairs(self.classes) do
|
||||
if class == 'warrior' then self.class_aspd_m = self.class_aspd_m*0.9
|
||||
elseif class == 'ranger' then self.class_aspd_m = self.class_aspd_m*1.4
|
||||
elseif class == 'mage' then self.class_aspd_m = self.class_aspd_m*1
|
||||
elseif class == 'healer' then self.class_aspd_m = self.class_aspd_m*0.5
|
||||
elseif class == 'cycler' then self.class_aspd_m = self.class_aspd_m*1 end
|
||||
elseif class == 'healer' then self.class_aspd_m = self.class_aspd_m*0.5 end
|
||||
end
|
||||
self.aspd = 1/((self.base_aspd + self.class_aspd_a + self.buff_aspd_a)*self.class_aspd_m*self.buff_aspd_m)
|
||||
|
||||
for _, class in ipairs(self.classes) do
|
||||
if class == 'warrior' then self.class_cycle_m = self.class_cycle_m*1
|
||||
elseif class == 'ranger' then self.class_cycle_m = self.class_cycle_m*1
|
||||
elseif class == 'mage' then self.class_cycle_m = self.class_cycle_m*1.25
|
||||
if class == 'mage' then self.class_cycle_m = self.class_cycle_m*1.25
|
||||
elseif class == 'healer' then self.class_cycle_m = self.class_cycle_m*1.1
|
||||
elseif class == 'cycler' then self.class_cycle_m = self.class_cycle_m*1.5 end
|
||||
end
|
||||
|
@ -192,17 +240,14 @@ function Unit:calculate_stats()
|
|||
if class == 'warrior' then self.class_def_m = self.class_def_m*1.25
|
||||
elseif class == 'ranger' then self.class_def_m = self.class_def_m*1.1
|
||||
elseif class == 'mage' then self.class_def_m = self.class_def_m*1.5
|
||||
elseif class == 'healer' then self.class_def_m = self.class_def_m*1.2
|
||||
elseif class == 'cycler' then self.class_def_m = self.class_def_m*1 end
|
||||
elseif class == 'healer' then self.class_def_m = self.class_def_m*1.2 end
|
||||
end
|
||||
self.def = (self.base_def + self.class_def_a + self.buff_def_a)*self.class_def_m*self.buff_def_m
|
||||
|
||||
for _, class in ipairs(self.classes) do
|
||||
if class == 'warrior' then self.class_mvspd_m = self.class_mvspd_m*0.9
|
||||
elseif class == 'ranger' then self.class_mvspd_m = self.class_mvspd_m*1.2
|
||||
elseif class == 'mage' then self.class_mvspd_m = self.class_mvspd_m*1
|
||||
elseif class == 'healer' then self.class_mvspd_m = self.class_mvspd_m*1
|
||||
elseif class == 'cycler' then self.class_mvspd_m = self.class_mvspd_m*1 end
|
||||
elseif class == 'seeker' then self.class_mvspd_m = self.class_mvspd_m*0.3 end
|
||||
end
|
||||
self.v = (self.base_mvspd + self.class_mvspd_a + self.buff_mvspd_a)*self.class_mvspd_m*self.buff_mvspd_m
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue