Hello,
I am simulating a ball being dragged around by a player. I'd like to create some animation to simulate that the ball is rotating (top-down view). I am trying to do that with a light source on top of the ball but I can't quite get it working correctly.
Looking for advice or some pointers to good tutorials on this subject.
Thanks in advance
function _init() player = {x=64, y=64} end function _update() local move_x, move_y = 0, 0 if btn(0) then move_x = -1 end if btn(1) then move_x = 1 end if btn(2) then move_y = -1 end if btn(3) then move_y = 1 end -- update player position and animation if move_x != 0 or move_y != 0 then player.x += move_x player.y += move_y end update_ball() end function _draw() cls() rectfill(player.x, player.y, player.x+8, player.y+8, 8) draw_ball() end --ball ball = {x=80, y=80, vx=0, vy=0, length=24, friction=0.9, mass=5, pull_force=0.2} ball.hitbox = {2,2,6,6} ball.name = "ball" ball.radius = 5 -- in ball initialization ball.light_pos = {x = ball.x, y = ball.y} function distance(x1, y1, x2, y2) return sqrt((x2-x1)^2 + (y2-y1)^2) end function update_ball() local dx = ball.x - player.x local dy = ball.y - player.y local dist = distance(ball.x, ball.y, player.x, player.y) if dist > ball.length then local angle = atan2(dx, dy) local pull_strength = (dist - ball.length) * ball.pull_force ball.vx -= cos(angle) * pull_strength ball.vy -= sin(angle) * pull_strength end ball.vx *= ball.friction ball.vy *= ball.friction ball.x += ball.vx ball.y += ball.vy if ball.vx != 0 or ball.vy != 0 then local move_dir_x = ball.vx > 0 and 1 or (ball.vx < 0 and -1 or 0) local move_dir_y = ball.vy > 0 and 1 or (ball.vy < 0 and -1 or 0) ball.light_pos.x += move_dir_x * 0.5 ball.light_pos.y += move_dir_y * 0.5 -- check if light has reached ball edge local light_dist = distance(ball.x, ball.y, ball.light_pos.x, ball.light_pos.y) if light_dist >= ball.radius+1 then -- move light along the direction of movement ball.rolled_under = true ball.roll_under_timer = ball.roll_under_frames -- reposition light on opposite side of ball and continue moving ball.light_pos.x = ball.x - move_dir_x * ball.radius ball.light_pos.y = ball.y - move_dir_y * ball.radius -- immediately continue moving in the same direction ball.light_pos.x += move_dir_x * 0.5 ball.light_pos.y += move_dir_y * 0.5 end end end function draw_ball() line(player.x+4, player.y+4, ball.x, ball.y, 13) circfill(ball.x, ball.y, 5, 1) -- light spot circfill(ball.light_pos.x, ball.light_pos.y, 1, 7) end |
Closer, but still quite wonky. Also realised that the light source wouldn't rotate (duh), so just putting a dot on the ball instead.
--ball ball = {x=80, y=80, vx=0, vy=0, length=24, friction=0.75, mass=5, pull_force=0.2} ball.hitbox = {2,2,6,6} ball.name = "ball" ball.radius = 5 ball.light_travel =0 -- in ball initialization ball.light_pos = {x = ball.x, y = ball.y} function distance(x1, y1, x2, y2) return sqrt((x2-x1)^2 + (y2-y1)^2) end function update_ball() local dx = ball.x - player.x local dy = ball.y - player.y local dist = distance(ball.x, ball.y, player.x, player.y) if dist > ball.length then local angle = atan2(dx, dy) local pull_strength = (dist - ball.length) * ball.pull_force ball.vx -= cos(angle) * pull_strength ball.vy -= sin(angle) * pull_strength end ball.vx *= ball.friction ball.vy *= ball.friction ball.x += ball.vx ball.y += ball.vy -- calculate movement angle if ball.vx != 0 or ball.vy != 0 then local angle = atan2(ball.vy, ball.vx) -- move light along the ball's movement trajectory ball.light_pos.x = ball.x + cos(angle) * ball.light_travel ball.light_pos.y = ball.y + sin(angle) * ball.light_travel -- when light reaches edge, reset travel ball.light_travel += 0.1 if ball.light_travel >= ball.radius then ball.light_travel = -ball.radius end end end function draw_ball() line(player.x+4, player.y+4, ball.x, ball.y, 13) circfill(ball.x, ball.y, 5, 7) -- light spot --circfill(ball.light_pos.x, ball.light_pos.y, 1, 7) pset(ball.light_pos.x, ball.light_pos.y,1) end |
Could you post a demo cart ? It would help visualizing what you are trying to do.
A word of warning : your distance function is likely to give wrong results due to integer overflow.
distance(0,0,128,128) will give you 0 for example.
(128*128+128*128)=-32768 , sqrt(-32768)=0
Your ball is not too big. A great way to sell the rotation could be to keep track of the three angles of rotation of the ball based on rolling, and color the ball accordingly. You could treat your ball as a transparent sphere with an embedded D20 , and color each pixel with the color of the visible face. Treating the ball as two halves of different colors also works great.
Here is the catridge
I realised I have my atan the wrong way around, it gets better with that fixed but doesn't really look like rolling to me.
[Please log in to post a comment]