Log In  

LAST VERSION as USED in R-type 1.4 after optimizing it a bit further:

--97 tokens with Scaling and arbitrary size
function pd_rotate(x,y,rot,mx,my,w,flip,scale)
  scale=scale or 1
  w*=scale*4

  local cs, ss = cos(rot)*.125/scale,sin(rot)*.125/scale
  local sx, sy = mx+cs*-w, my+ss*-w
  local hx = flip and -w or w

  local halfw = -w
  for py=y-w, y+w do
    tline(x-hx, py, x+hx, py, sx-ss*halfw, sy+cs*halfw, cs, ss)
    halfw+=1
  end
end

This is a general-purpose sprite rotation function using tline with support for scaling and flipping

Cart #tline_sprite_rotation-5 | 2022-04-30 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
47

It always draw a screen-oriented rectangular area, (centered at x,y) large enough (w) to contain the rotated tiles (centered at mx,my), and calculates the rotated (rot 0 to 1) tline coordinates and deltas.

The catch is that you need to have the sprite in the map and must leave "clearance-space" around the map part to be rotated (matching the largest side of the sprite or you get some additional map tiles drawn as well, visible in pink in the example). But you can just prepare one rotating area and just swap tiles with mset().

LAST EDITED for a mistake that was messing up mx and my

P#78451 2020-06-24 05:59 ( Edited 2022-04-30 06:52)

1

see https://www.lexaloffle.com/bbs/?tid=37561 for a generic purpose tlne rotation without any constraints

P#78458 2020-06-24 08:21

Thanks again @TheRoboZ for posting this.
I've just started playing with it as a successor to Fred72's legendary RSPR() routine I'd been using for ages.

Early days, but looks like it might do the trick
(although, due to the way I render shadows, etc. I might end up using more tokens - might be worth it, depends on the perf improvement!)

Thanks again! 🤓👍

UPDATE: Woah, looks like mine + Fred's comments overlapped!
Thx @freds72, I'll give that another look, but I thought the token count was higher and/or inc. features I do not require (as all my current needs are for single, 8x8 sprites) 🤔

P#78459 2020-06-24 08:35 ( Edited 2020-06-24 10:14)
1

ok ok I see where I can have a much leaner version. Stay tuned!

P#78461 2020-06-24 10:37
2

I noticed a small optimization after posting:

--150 tokens

function draw_rotated_rect(x,y,sw_rot,mx,my,w,h)
    local dx, dy, r, cs, ss = 0, 0, max(w,h)/2, cos(sw_rot), -sin(sw_rot)
    if w>h then dy = (w-h)/2 else dx = (h-w)/2 end
    local ssx, ssy, cx, cy = mx - 0.3 -dx, my - 0.3 -dy, mx+r-dx, my+r-dy

    ssy -=cy
    ssx -=cx

    local delta_px = max(-ssx,-ssy)*8

    --this just draw a bounding box to show the exact draw area
    rect(x-delta_px,y-delta_px,x+delta_px,y+delta_px,5)

    local sx, sy =  cs * ssx + cx, -ss * ssx + cy

    for py = y-delta_px, y+delta_px do
        tline(x-delta_px, py, x+delta_px, py, sx + ss * ssy, sy + cs * ssy, cs/8, -ss/8)
        ssy+=1/8
    end
end

--108 tokens

function draw_rotated_square(x,y,sw_rot,mx,my,r)    
    local cs, ss = cos(sw_rot), -sin(sw_rot)    
    local ssx, ssy, cx, cy = mx - 0.3, my - 0.3, mx+r/2, my+r/2

    ssy -=cy
    ssx -=cx

    local delta_px = -ssx*8

    --this just draw a bounding box to show the exact draw area
    rect(x-delta_px,y-delta_px,x+delta_px,y+delta_px,5)

    local sx, sy =  cs * ssx + cx, -ss * ssx + cy

    for py = y-delta_px, y+delta_px do
        tline(x-delta_px, py, x+delta_px, py, sx + ss * ssy, sy + cs * ssy, cs/8, -ss/8)
        ssy+=1/8
    end
end

and for fixed 8x8 size you can optimize it even more.

P#78463 2020-06-24 11:05 ( Edited 2020-06-24 11:23)
3

Hey @Liquidream I added a more general purpose one with support for flip and scaling after using it in my game

function draw_rotated_tile(x,y,rot,mx,my,w,flip,scale)
  scale = scale or 1
  w+=.8
  local halfw, cx  = scale*-w/2, mx + w/2 -.4
  local cs, ss, cy = cos(rot)/scale, -sin(rot)/scale, my-halfw/scale-.4
  local sx, sy, hx, hy = cx + cs*halfw, cy - ss*halfw, w*(flip and -4 or 4)*scale, w*4*scale

  --this just draw a bounding box to show the exact draw area
  rect(x-hx,y-hy,x+hx,y+hy,5)

  for py = y-hy, y+hy do
    tline(x-hx, py, x+hx, py, sx + ss*halfw, sy + cs*halfw, cs/8, -ss/8)
    halfw+=1/8
  end
end
P#80283 2020-08-03 00:23

Thanks a lot @TheRoboZ 🤓👍

P#80293 2020-08-03 04:57

Since this has been used in a couple carts, here is the last updated version as used in R-type:

--123 tokens with scaling and arbitrary size
function pd_rotate(x,y,rot,mx,my,w,flip,scale)
scale=scale or 1
local halfw, cx=scale-w/2, mx + .5
local cy,cs,ss=my-halfw/scale,cos(rot)/scale,sin(rot)/scale
local sx, sy, hx, hy=cx+cs
halfw, cy+sshalfw, w(flip and -4 or 4)scale, w4scale
for py=y-hy, y+hy do
tline(x-hx, py, x+hx, py, sx -ss
halfw, sy + cs*halfw, cs/8, ss/8)
halfw+=.125
end
end

P#105732 2022-01-27 07:25
1

Since this has been used in a couple carts, here is the last updated version as used in R-type:

--123 tokens with scaling and arbitrary size
function pd_rotate(x,y,rot,mx,my,w,flip,scale)
  scale=scale or 1
  local halfw, cx=scale*-w/2, mx + .5
  local cy,cs,ss=my-halfw/scale,cos(rot)/scale,sin(rot)/scale
  local sx, sy, hx, hy=cx+cs*halfw, cy+ss*halfw, w*(flip and -4 or 4)*scale, w*4*scale
  for py=y-hy, y+hy do
  tline(x-hx, py, x+hx, py, sx -ss*halfw, sy + cs*halfw, cs/8, ss/8)
  halfw+=.125
  end
end
P#105733 2022-01-27 07:25 ( Edited 2022-01-27 07:26)
2

Cart #tline_sprite_rotation_mod-0 | 2022-01-31 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
2

Here is @simonwilson's rocket. I wanted to see if this rotation was any better with less jaggies than the one he wrote. I'm not seeing a difference.

P#106060 2022-01-31 18:47
1

@dw817 For R-type I was constraining rotation angles to fixed step (when drawn, calculation uses continuous rotation)

function pd_rotate(x,y,rot,mx,my,w,flip,scale)
  local step = 1/16
  scale=scale or 1
  rot=rot\step * step
  local halfw, cx=scale*-w/2, mx + .5
  local cy,cs,ss=my-halfw/scale,cos(rot)/scale,sin(rot)/scale
  local sx, sy, hx, hy=cx+cs*halfw, cy+ss*halfw, w*(flip and -4 or 4)*scale, w*4*scale
  for py=y-hy, y+hy do
  tline(x-hx, py, x+hx, py, sx -ss*halfw, sy + cs*halfw, cs/8, ss/8)
  halfw+=.125
  end
end

Liek this you get 22.5, 45, etc...
still there is some intrinsic jagginess that sometimes depends on the sprite (I got the rocket from the cart and it was not symmetrical, so I fixed it here). For r-type homing missiles I had a problem when at some angles they looked weird when horizontal, so I drew them with an equal but opposite offset and they appear straight when rotated

You can also add a bit of manual anti-aliasing when drawing the sprite to hide it a bit (bottom rocket), but for real-time smoothing or dithering I have no idea.

P#106112 2022-02-01 11:38

That =IS= better, @TheRoboZ. I figured intelligent dithering would fix a lot of the jagginess. Well done.

P#106130 2022-02-01 17:19
1

@Xeonic it uses tline so it is reading from the map area. You need to put your sprite to be rotated in an area of the map editor. Check the updated cart and description above.

P#111024 2022-04-29 04:15
1

Sorry, there was a typo in this line:

local sx, sy = mx+cs-w, my+ss-w

you need to add half w to the starting my coordinate when calling the function and not inside the rotation code. Anyway see the updated cart

P#111093 2022-04-30 06:36 ( Edited 2022-04-30 06:53)

@TheRoboZ in the code of the above cart you have:

if (not(o and (rot<.25 or rot >.75) and py>y+4))

What is this for?

It was causing issues for me, taking it out solved them, but I was just wondering what it's purpose is...

(Also note that is a text "o" and not a numeric 0)

P#121384 2022-11-25 12:54 ( Edited 2022-11-25 12:56)
1

@mika76 sorry it is a leftover from how I was using it in a game cart that I forgot to remove, it’s not part of the rotation code

P#121401 2022-11-26 03:49

Oh whew :-)

P#121409 2022-11-26 09:12

Hey everyone! I need help with math. 😦

I'm struggling trying to rotate and mirror(or flip) a sprite tile. I am using the code from TheRoboZ But am struggling to get the Y axis flipping as well as the X axis does.

Here is the code and an attached gif to show what I'm talking about.

rot=0/360
snek_head={x=30, y=20}
dir=3

function pd_rotate(x,y,rot,mx,my,w,flp,scale)
  scale=scale or 1
  w*=scale*4
  halfw = -w

  local cs, ss = cos(rot)*.125/scale, sin(rot)*.125/scale
  local sx, sy = mx+cs*-w, my+ss*-w

  if dir>1 then -- left or right
   hx = flp and -w or w 
  else -- up or down
   hx =-w
  end 

  for py=y-w, y+w do
    --TLINE(X0, Y0, X1, Y1, MX, MY, [MDX, MDY], [LAYERS])
    tline(x-hx, py, x+hx, py, sx-ss*halfw, sy+cs*halfw, cs, ss)
    halfw+=1
  end

  print("hx" .. hx, 7)
end

function _draw()
  cls()-- 2=n180(2) 3=s360(0) 1=e270(3) 0=w90(1)
  if btnp(0) and dir ~= 1 then dir = 0 rot=3/4 
    elseif btnp(1) and dir ~= 0 then dir = 1 rot=1/4 
  elseif btnp(2) and dir ~= 3 then dir = 2 rot=2/4
  elseif btnp(3) and dir ~= 2 then dir = 3 rot=0/4
  end
  if dir==0 then snek_head.x-=1 
  elseif dir==1 then snek_head.x+=1 
  elseif dir==2 then snek_head.y-=1 
  elseif dir==3 then snek_head.y+=1 
  end
  if t()%2>1 then flp=true end 
  if t()%2<1 then flp=false end

  pd_rotate(snek_head.x,snek_head.y, rot,4.5,8.5,1,flp,1)
end

I'm trying to accomplish a "wiggle" going left to right similar to the way the "wiggle" works top to bottom.

I think the problem lies somewhere in how I'm calling the tline but I'm unsure how.

Any math related solutions would be super appreciated! I'm not interested in just adding another sprite for this.

UPDATE::::::::::::::::::::::::

Follow up to my question with the updated solution thanks to @freds72 telling me to use SPR instead of the Rotate function

dir=3
snek_head={x=20, y=20}

function _draw()
  cls()-- 2=n180(2) 3=s360(0) 1=e270(3) 0=w90(1)
  if btnp(0) and dir ~= 1 then dir = 0
   elseif btnp(1) and dir ~= 0 then dir = 1
   elseif btnp(2) and dir ~= 3 then dir = 2
   elseif btnp(3) and dir ~= 2 then dir = 3
  end
  if dir==0 then snek_head.x-=1 snek_head.n=18 flp_x=true
   elseif dir==1 then snek_head.x+=1 snek_head.n=18 flp_x=false
   elseif dir==2 then snek_head.y-=1 snek_head.n=17 flp_y=true
   elseif dir==3 then snek_head.y+=1 snek_head.n=17 flp_y=false
  end
  if dir>1 then--up/down 
    if t()%1>.5 then flp_x=true
     else flp_x=false
    end
  end
  if dir<2 then--left/right
    if t()%1>.5 then flp_y=true
     else flp_y=false
    end
  end
    spr(snek_head.n, snek_head.x, snek_head.y,1,1,flp_x,flp_y)
end
P#133915 2023-09-04 13:20 ( Edited 2023-09-04 14:08)

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2024-03-28 08:14:59 | 0.087s | Q:47