mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-25 05:25:14 +00:00
Football improvements
Rewrote all of the ball-to-player interactions Player collisions are better now Attacks affect the ball in different ways Centered camera during the countdown period Players lose their velocity during the countdown period
This commit is contained in:
parent
180fe3a8a0
commit
02ffca130e
1 changed files with 193 additions and 99 deletions
|
@ -13,6 +13,19 @@ ballWaterDrag = 0.9
|
||||||
ballParallelInertia = 0.3
|
ballParallelInertia = 0.3
|
||||||
ballPerpendicularInertia = 1
|
ballPerpendicularInertia = 1
|
||||||
|
|
||||||
|
ballActionValues = {
|
||||||
|
[ACT_WATER_PUNCH] = { xz = 20, y = 40, directionless = false },
|
||||||
|
[ACT_MOVE_PUNCHING] = { xz = 35, y = 0, directionless = false },
|
||||||
|
[ACT_PUNCHING] = { xz = 35, y = 0, directionless = false },
|
||||||
|
[ACT_GROUND_POUND] = { xz = 40, y = 40, directionless = true },
|
||||||
|
[ACT_GROUND_POUND_LAND] = { xz = 40, y = 40, directionless = true },
|
||||||
|
[ACT_JUMP_KICK] = { xz = 10, y = 32, directionless = false },
|
||||||
|
[ACT_SLIDE_KICK_SLIDE] = { xz = -7, y = 25, directionless = false },
|
||||||
|
[ACT_SLIDE_KICK] = { xz = -7, y = 25, directionless = false },
|
||||||
|
[ACT_LONG_JUMP] = { xz = 0, y = 0, directionless = false },
|
||||||
|
[ACT_CROUCH_SLIDE] = { xz = 0, y = 0, directionless = false },
|
||||||
|
}
|
||||||
|
|
||||||
---------------
|
---------------
|
||||||
-- globals --
|
-- globals --
|
||||||
---------------
|
---------------
|
||||||
|
@ -25,6 +38,17 @@ gInitializeBalls = {}
|
||||||
-- utils --
|
-- utils --
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
function clamp(x, a, b)
|
||||||
|
if x < a then return a end
|
||||||
|
if x > b then return b end
|
||||||
|
return x
|
||||||
|
end
|
||||||
|
|
||||||
|
function vec3f_degrees_between(a, b)
|
||||||
|
local ansAgain = math.acos(vec3f_dot(a, b) / (vec3f_length(a) * vec3f_length(b)))
|
||||||
|
return math.deg(ansAgain)
|
||||||
|
end
|
||||||
|
|
||||||
function my_global_index()
|
function my_global_index()
|
||||||
return gNetworkPlayers[gMarioStates[0].playerIndex].globalIndex
|
return gNetworkPlayers[gMarioStates[0].playerIndex].globalIndex
|
||||||
end
|
end
|
||||||
|
@ -182,116 +206,183 @@ function bhv_ball_init(obj)
|
||||||
end
|
end
|
||||||
|
|
||||||
function bhv_ball_player_collision(obj)
|
function bhv_ball_player_collision(obj)
|
||||||
|
local alterPos = { x = 0, y = 0, z = 0}
|
||||||
|
|
||||||
local m = nearest_mario_state_to_object(obj)
|
local m = nearest_mario_state_to_object(obj)
|
||||||
|
if m == nil then return alterPos end
|
||||||
local player = m.marioObj
|
local player = m.marioObj
|
||||||
|
if player == nil then return alterPos end
|
||||||
|
|
||||||
local playerRadius = 37
|
local playerRadius = 37
|
||||||
local playerHeight = 160 / 2
|
local playerHeight = 160
|
||||||
local alterPos = { x = 0, y = 0, z = 0 }
|
|
||||||
|
local objPoint = { x = obj.oPosX, y = obj.oPosY, z = obj.oPosZ }
|
||||||
local v = { x = obj.oVelX, y = obj.oVelY, z = obj.oVelZ }
|
local v = { x = obj.oVelX, y = obj.oVelY, z = obj.oVelZ }
|
||||||
local playerBallRadius = ballRadius
|
|
||||||
|
|
||||||
-- figure out player-to-ball radius
|
-- figure out player-to-ball radius
|
||||||
if (m.action & ACT_FLAG_ATTACKING) ~= 0 then
|
local alterBallFlags = (ACT_FLAG_ATTACKING | ACT_FLAG_BUTT_OR_STOMACH_SLIDE | ACT_FLAG_DIVING)
|
||||||
|
local playerBallRadius = ballRadius
|
||||||
|
if ballActionValues[m.action] ~= nil or (m.action & alterBallFlags) ~= 0 then
|
||||||
playerBallRadius = playerBallRadius + 50
|
playerBallRadius = playerBallRadius + 50
|
||||||
end
|
end
|
||||||
|
|
||||||
-- figure out if our height collides
|
------------------------------------------------
|
||||||
local heightOverlap = math.abs((player.oPosY + playerHeight * 0.5) - obj.oPosY) < (playerHeight + playerBallRadius)
|
-- calculate position and determine collision --
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
-- figure out if our radius collides
|
-- calculate cylinder values
|
||||||
local xdiff = player.oPosX - obj.oPosX
|
local cylY1 = player.oPosY + playerRadius
|
||||||
local zdiff = player.oPosZ - obj.oPosZ
|
local cylY2 = player.oPosY + playerHeight - playerRadius
|
||||||
local xzmag = math.sqrt(xdiff * xdiff + zdiff * zdiff)
|
local cylPoint = { x = player.oPosX, y = clamp(obj.oPosY, cylY1, cylY2), z = player.oPosZ }
|
||||||
local radiusOverlap = xzmag <= (playerRadius + playerBallRadius)
|
local cylDist = vec3f_dist(cylPoint, objPoint)
|
||||||
local xzdiff = (playerRadius + playerBallRadius) - xzmag
|
|
||||||
|
|
||||||
-- check if player should affect ball
|
-- check for collision
|
||||||
if heightOverlap and radiusOverlap then
|
if cylDist > (playerBallRadius + playerRadius) then
|
||||||
-- detect if the local player touched it
|
return alterPos
|
||||||
if m.playerIndex == 0 then
|
end
|
||||||
gBallTouchedLocal = true
|
|
||||||
|
gBallTouchedLocal = (m.playerIndex == 0)
|
||||||
|
|
||||||
|
local vDifference = { x = objPoint.x - cylPoint.x, y = objPoint.y - cylPoint.y, z = objPoint.z - cylPoint.z }
|
||||||
|
local differenceDir = { x = vDifference.x, y = vDifference.y, z = vDifference.z }
|
||||||
|
vec3f_normalize(differenceDir)
|
||||||
|
|
||||||
|
alterPos.x = (cylPoint.x + differenceDir.x * (playerBallRadius + playerRadius + 1)) - objPoint.x
|
||||||
|
alterPos.y = (cylPoint.y + differenceDir.y * (playerBallRadius + playerRadius + 1)) - objPoint.y
|
||||||
|
alterPos.z = (cylPoint.z + differenceDir.z * (playerBallRadius + playerRadius + 1)) - objPoint.z
|
||||||
|
|
||||||
|
-----------------------------------------
|
||||||
|
-- figure out player's attack velocity --
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
local vPlayer = { x = player.oVelX, y = player.oVelY, z = player.oVelZ }
|
||||||
|
local playerTheta = (m.faceAngle.y / 0x8000) * math.pi
|
||||||
|
|
||||||
|
-- have attacks alter velocity further
|
||||||
|
local alterXz = 0
|
||||||
|
local alterY = 0
|
||||||
|
local alterDirectionless = false
|
||||||
|
|
||||||
|
if ballActionValues[m.action] ~= nil then
|
||||||
|
alterXz = ballActionValues[m.action].xz
|
||||||
|
alterY = ballActionValues[m.action].y
|
||||||
|
alterDirectionless = ballActionValues[m.action].directionless
|
||||||
|
elseif ((m.action & (ACT_FLAG_BUTT_OR_STOMACH_SLIDE | ACT_FLAG_DIVING)) ~= 0) or (m.action == ACT_SLIDE_KICK_SLIDE) or (m.action == ACT_SLIDE_KICK) then
|
||||||
|
-- dive or slide sends it upward, and slows xz
|
||||||
|
alterXz = -7
|
||||||
|
alterY = 25
|
||||||
|
elseif (m.action & ACT_FLAG_ATTACKING) ~= 0 then
|
||||||
|
-- other attacks should just do something reasonable
|
||||||
|
alterXz = 10
|
||||||
|
alterY = 10
|
||||||
|
end
|
||||||
|
|
||||||
|
-- adjust angle
|
||||||
|
local theta = playerTheta
|
||||||
|
if alterDirectionless and differenceDir.z ~= 0 then
|
||||||
|
theta = math.atan2(differenceDir.x, differenceDir.z)
|
||||||
|
end
|
||||||
|
|
||||||
|
vPlayer.x = vPlayer.x + math.sin(theta) * alterXz
|
||||||
|
vPlayer.z = vPlayer.z + math.cos(theta) * alterXz
|
||||||
|
if vPlayer.y < alterY then vPlayer.y = vPlayer.y + alterY end
|
||||||
|
|
||||||
|
local vPlayerMag = vec3f_length(vPlayer)
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
-- figure out which velocity interaction to do --
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
local v = { x = obj.oVelX, y = obj.oVelY, z = obj.oVelZ }
|
||||||
|
|
||||||
|
local doReflection = (vPlayerMag == 0)
|
||||||
|
|
||||||
|
-- make sure ball is offset in the vPlayer direction
|
||||||
|
if not doReflection then
|
||||||
|
local objCylDir = { x = cylPoint.x - objPoint.x, y = cylPoint.y - objPoint.y, z = cylPoint.z - objPoint.z }
|
||||||
|
local objCylDirXZ = { x = objCylDir.x, y = 0, z = objCylDir.z }
|
||||||
|
local objCylDirMag = vec3f_length(objCylDir)
|
||||||
|
|
||||||
|
local vPlayerXZ = { x = vPlayer.x, y = 0, z = vPlayer.z }
|
||||||
|
local vPlayerXZMag = vec3f_length(vPlayerXZ)
|
||||||
|
|
||||||
|
if objCylDirMag > 0 and vPlayerXZMag > 0 then
|
||||||
|
doReflection = (vec3f_degrees_between(vPlayer, objCylDir)) <= 120
|
||||||
|
and (vec3f_degrees_between(vPlayerXZ, objCylDirXZ)) <= 120
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- detect hit from top
|
--------------------------------------
|
||||||
local heightMag = math.abs(obj.oPosY - player.oPosY - 167.5)
|
-- calculate velocity (interaction) --
|
||||||
if obj.oVelY <= 0 and (heightMag < xzmag or xzmag < 1) and heightMag < playerBallRadius then
|
--------------------------------------
|
||||||
alterPos.y = heightMag + 1
|
|
||||||
obj.oVelY = obj.oVelY * -ballRestitution
|
|
||||||
if math.abs(obj.oVelX) < math.abs(xdiff * 0.2) then obj.oVelX = -xdiff * 0.2 end
|
|
||||||
if obj.oVelY < player.oVelY + 5 then obj.oVelY = player.oVelY + 5 end
|
|
||||||
if math.abs(obj.oVelZ) < math.abs(zdiff * 0.2) then obj.oVelZ = -zdiff * 0.2 end
|
|
||||||
return alterPos
|
|
||||||
end
|
|
||||||
|
|
||||||
-- prevent division by zero
|
if not doReflection then
|
||||||
if xzmag < 1 then
|
local vPlayerDir = { x = vPlayer.x, y = vPlayer.y, z = vPlayer.z }
|
||||||
xdiff = 1
|
vec3f_normalize(vPlayerDir)
|
||||||
zdiff = 0
|
|
||||||
xzmag = 1
|
|
||||||
end
|
|
||||||
|
|
||||||
-- reflect the current velocity against the player
|
-- split velocity into parallel/perpendicular to normal
|
||||||
local n = { x = xdiff / xzmag, y = 0, z = zdiff / xzmag }
|
local perpendicular = vec3f_project(v, vPlayerDir)
|
||||||
local perpendicular = vec3f_project(v, n)
|
|
||||||
local parallel = { x = v.x - perpendicular.x, y = v.y - perpendicular.y, z = v.z - perpendicular.z }
|
local parallel = { x = v.x - perpendicular.x, y = v.y - perpendicular.y, z = v.z - perpendicular.z }
|
||||||
|
|
||||||
|
-- apply friction
|
||||||
|
vec3f_mul(parallel, 0.5)
|
||||||
|
|
||||||
|
local parallelMag = vec3f_length(parallel)
|
||||||
|
local perpendicularMag = vec3f_length(perpendicular)
|
||||||
|
|
||||||
|
if perpendicularMag == 0 or perpendicularMag < vPlayerMag then
|
||||||
|
vec3f_copy(perpendicular, vPlayer)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- reflect velocity along normal
|
||||||
|
local reflect = {
|
||||||
|
x = parallel.x + perpendicular.x,
|
||||||
|
y = parallel.y + perpendicular.y,
|
||||||
|
z = parallel.z + perpendicular.z
|
||||||
|
}
|
||||||
|
|
||||||
|
-- set new velocity
|
||||||
|
obj.oVelX = reflect.x
|
||||||
|
obj.oVelY = reflect.y
|
||||||
|
obj.oVelZ = reflect.z
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------
|
||||||
|
-- calculate velocity (reflection) --
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
if doReflection then
|
||||||
|
-- split velocity into parallel/perpendicular to normal
|
||||||
|
local perpendicular = vec3f_project(v, differenceDir)
|
||||||
|
local parallel = { x = v.x - perpendicular.x, y = v.y - perpendicular.y, z = v.z - perpendicular.z }
|
||||||
|
|
||||||
|
-- apply friction and restitution
|
||||||
|
vec3f_mul(parallel, ballFriction)
|
||||||
|
vec3f_mul(perpendicular, ballRestitution)
|
||||||
|
|
||||||
|
-- play sounds
|
||||||
|
local parallelLength = vec3f_length(parallel)
|
||||||
|
local perpendicularLength = vec3f_length(perpendicular)
|
||||||
|
|
||||||
|
if perpendicularLength > 5 then
|
||||||
|
cur_obj_play_sound_2(SOUND_GENERAL_BOX_LANDING_2)
|
||||||
|
elseif parallelLength > 3 then
|
||||||
|
cur_obj_play_sound_2(SOUND_ENV_SLIDING)
|
||||||
|
end
|
||||||
|
|
||||||
|
local pushOutMag = 10
|
||||||
|
|
||||||
|
-- reflect velocity along normal
|
||||||
local reflect = {
|
local reflect = {
|
||||||
x = parallel.x - perpendicular.x,
|
x = parallel.x - perpendicular.x,
|
||||||
y = parallel.y - perpendicular.y,
|
y = parallel.y - perpendicular.y,
|
||||||
z = parallel.z - perpendicular.z
|
z = parallel.z - perpendicular.z
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.oVelX = reflect.x
|
-- set new velocity
|
||||||
obj.oVelZ = reflect.z
|
obj.oVelX = reflect.x + differenceDir.x * pushOutMag
|
||||||
|
obj.oVelY = reflect.y + differenceDir.y * pushOutMag
|
||||||
-- move ball outside of player
|
obj.oVelZ = reflect.z + differenceDir.z * pushOutMag
|
||||||
alterPos.x = -xdiff / xzmag * (xzdiff + 1)
|
|
||||||
alterPos.z = -zdiff / xzmag * (xzdiff + 1)
|
|
||||||
|
|
||||||
-- when ball is moved outside of player, give it speed in that direction
|
|
||||||
local addVel = { x = alterPos.x * 0.25, y = 0, z = alterPos.z * 0.25 }
|
|
||||||
local addVelMag = math.sqrt(addVel.x * addVel.x + addVel.z * addVel.z)
|
|
||||||
if addVelMag > 10 then
|
|
||||||
addVel.x = addVel.x / addVelMag * 10
|
|
||||||
addVel.z = addVel.z / addVelMag * 10
|
|
||||||
end
|
|
||||||
|
|
||||||
-- also obtain the player's speed
|
|
||||||
addVel.x = addVel.x + player.oVelX
|
|
||||||
addVel.z = addVel.z + player.oVelZ
|
|
||||||
|
|
||||||
-- have attacks alter velocity further
|
|
||||||
if (m.action == ACT_WATER_PUNCH) then
|
|
||||||
-- water punch launches it
|
|
||||||
addVel.x = addVel.x + xdiff / xzmag * -20
|
|
||||||
addVel.z = addVel.z + zdiff / xzmag * -20
|
|
||||||
obj.oVelY = obj.oVelY + 40
|
|
||||||
if obj.oVelY > 40 then obj.oVelY = 40 end
|
|
||||||
elseif (m.action & ACT_FLAG_ATTACKING) ~= 0 then
|
|
||||||
if (m.action == ACT_MOVE_PUNCHING) or (m.action == ACT_PUNCHING) or (m.action == ACT_GROUND_POUND) then
|
|
||||||
-- normal punch or ground pound launches it
|
|
||||||
addVel.x = addVel.x + xdiff / xzmag * -30
|
|
||||||
addVel.z = addVel.z + zdiff / xzmag * -30
|
|
||||||
if m.action == ACT_GROUND_POUND then
|
|
||||||
obj.oVelY = obj.oVelY + 25
|
|
||||||
if obj.oVelY > 25 then obj.oVelY = 25 end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- other attacks send it upward, and decrease the xz force
|
|
||||||
addVel.x = addVel.x - player.oVelX * 0.3
|
|
||||||
addVel.z = addVel.z - player.oVelZ * 0.3
|
|
||||||
obj.oVelY = obj.oVelY + 25
|
|
||||||
if obj.oVelY > 25 then obj.oVelY = 25 end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- apply attack velocity
|
|
||||||
-- this isn't the correct way to do this but whatever
|
|
||||||
addVelMag = math.sqrt(addVel.x * addVel.x + addVel.z * addVel.z)
|
|
||||||
local v = { x = obj.oVelX, y = 0, z = obj.oVelZ }
|
|
||||||
if vec3f_length(v) < addVelMag * 1.5 then
|
|
||||||
obj.oVelX = addVel.x
|
|
||||||
obj.oVelZ = addVel.z
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return alterPos
|
return alterPos
|
||||||
|
@ -346,13 +437,13 @@ function bhv_ball_loop(obj)
|
||||||
|
|
||||||
|
|
||||||
-- detect player collisions
|
-- detect player collisions
|
||||||
local alter = bhv_ball_player_collision(obj)
|
local alterPos = bhv_ball_player_collision(obj)
|
||||||
|
|
||||||
-- alter end-point based on player collisions
|
-- alter end-point based on player collisions
|
||||||
local a = { x = obj.oPosX, y = obj.oPosY, z = obj.oPosZ }
|
local a = { x = obj.oPosX, y = obj.oPosY, z = obj.oPosZ }
|
||||||
local v = { x = obj.oVelX, y = obj.oVelY, z = obj.oVelZ }
|
local v = { x = obj.oVelX, y = obj.oVelY, z = obj.oVelZ }
|
||||||
local b = { x = v.x, y = v.y, z = v.z }
|
local b = { x = v.x, y = v.y, z = v.z }
|
||||||
vec3f_sum(b, b, alter)
|
vec3f_sum(b, b, alterPos)
|
||||||
|
|
||||||
-- regular movement
|
-- regular movement
|
||||||
local info = collision_find_surface_on_ray(
|
local info = collision_find_surface_on_ray(
|
||||||
|
@ -772,8 +863,8 @@ function gamemode_active()
|
||||||
sStateTimer = sOverTimeout
|
sStateTimer = sOverTimeout
|
||||||
else
|
else
|
||||||
-- set sparkle
|
-- set sparkle
|
||||||
if scorerNp ~= nil then
|
local scorerS = gPlayerSyncTable[scorerNp.localIndex]
|
||||||
local scorerS = gPlayerSyncTable[scorerNp.localIndex]
|
if scorerNp ~= nil and scorerS.team == scoringTeam then
|
||||||
scorerS.sparkle = true
|
scorerS.sparkle = true
|
||||||
end
|
end
|
||||||
gGlobalSyncTable.gameState = GAME_STATE_SCORE
|
gGlobalSyncTable.gameState = GAME_STATE_SCORE
|
||||||
|
@ -1021,12 +1112,10 @@ function mario_update_local(m)
|
||||||
local np = gNetworkPlayers[m.playerIndex]
|
local np = gNetworkPlayers[m.playerIndex]
|
||||||
local s = gPlayerSyncTable[m.playerIndex]
|
local s = gPlayerSyncTable[m.playerIndex]
|
||||||
|
|
||||||
--if (m.controller.buttonPressed & D_JPAD) ~= 0 then
|
if (m.controller.buttonPressed & D_JPAD) ~= 0 then
|
||||||
-- print(m.pos.x, m.pos.y, m.pos.z)
|
--print(m.pos.x, m.pos.y, m.pos.z)
|
||||||
-- sSoccerBall.oPosX = m.pos.x
|
--sSoccerBall = spawn_or_move_ball(m.pos.x, m.pos.y, m.pos.z)
|
||||||
-- sSoccerBall.oPosY = m.pos.y - 100
|
end
|
||||||
-- sSoccerBall.oPosZ = m.pos.z
|
|
||||||
--end
|
|
||||||
|
|
||||||
-- force players into certain positions and angles
|
-- force players into certain positions and angles
|
||||||
if gGlobalSyncTable.gameState == GAME_STATE_WAIT then
|
if gGlobalSyncTable.gameState == GAME_STATE_WAIT then
|
||||||
|
@ -1043,6 +1132,9 @@ function mario_update_local(m)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- center camera
|
||||||
|
m.controller.buttonDown = m.controller.buttonDown | L_TRIG
|
||||||
|
|
||||||
-- figure out spawn position
|
-- figure out spawn position
|
||||||
local teamTheta = (3.14 / -2)
|
local teamTheta = (3.14 / -2)
|
||||||
local teamDistance = 1550
|
local teamDistance = 1550
|
||||||
|
@ -1073,11 +1165,13 @@ function mario_update_local(m)
|
||||||
m.vel.x = 0
|
m.vel.x = 0
|
||||||
m.vel.y = 0
|
m.vel.y = 0
|
||||||
m.vel.z = 0
|
m.vel.z = 0
|
||||||
|
m.forwardVel = 0
|
||||||
|
m.slideVelX = 0
|
||||||
|
m.slideVelZ = 0
|
||||||
set_mario_action(m, ACT_READING_AUTOMATIC_DIALOG, 0)
|
set_mario_action(m, ACT_READING_AUTOMATIC_DIALOG, 0)
|
||||||
|
|
||||||
-- fix vanilla camera
|
-- fix vanilla camera
|
||||||
if m.area.camera.mode == CAMERA_MODE_WATER_SURFACE then
|
if m.area.camera.mode == CAMERA_MODE_WATER_SURFACE then
|
||||||
print(m.area.camera.mode)
|
|
||||||
set_camera_mode(m.area.camera, CAMERA_MODE_FREE_ROAM, 1)
|
set_camera_mode(m.area.camera, CAMERA_MODE_FREE_ROAM, 1)
|
||||||
end
|
end
|
||||||
elseif m.action == ACT_READING_AUTOMATIC_DIALOG then
|
elseif m.action == ACT_READING_AUTOMATIC_DIALOG then
|
||||||
|
|
Loading…
Reference in a new issue