Posted: 29th Nov 2021 14:27
I'm trying to place an animated sprite between a gun with a turret and enemy sprites, rotating, scaling and positioning it so that it connects the two.
I've been playing with it all weekend but it isn't quite right.

I thought my maths was wrong but this morning I wrote some stand-alone code to isolate the issue and see if I could determine what was wrong but that works perfectly, so the issue is somewhere in my code and I just can't see it.
If any of you have any spare time, would you mind casting your eyes over the code and seeing if you can spot where I'm going wrong?

Here you can see that the targeting is slightly off:


And here is some stand-along code that work perfectly:
+ Code Snippet
SetDisplayAspect(1)
SetWindowSize(800, 400, 0)
SetScissor(0, 0, 0, 0)
SetSyncRate(60, 0)

global gun, turret, tgt, laser

gun = CreateSprite(0)
SetSpriteSize(gun, 5, 5)
SetSpriteColor(gun, 0, 255, 0, 255)
SetSpritePositionByOffset(gun, 25, 50)

turret = CreateSprite(0)
SetSpriteSize(turret, 2, 2)
SetSpriteColor(turret, 255, 0, 0, 255)

tgt = CreateSprite(0)
SetSpriteSize(tgt, 5, 5)
SetSpriteColor(tgt, 0, 0, 255, 255)

laser = CreateSprite(0)
SetSpriteColor(laser, 0, 255, 255, 255)
SetSpriteOffset(laser, GetSpriteWidth(laser)*0.5, 0)


repeat
	MoveTarget(Timer() * 100)
	UpdateGun()
	ShowLaser(GetPointerState())
	
	sync()
until GetRawMouseRightPressed()



function MoveTarget(count)
	dist# = sin(count/3.0) * 50
	x# = 50 + sin(count) * dist#
	y# = 50 - cos(count) * dist#
	SetSpritePositionByOffset(tgt, x#, y#) 
endfunction


function UpdateGun()
	angle# = ATanFull(GetSpriteXByOffset(gun)-GetSpriteXByOffset(tgt), GetSpriteYByOffset(gun)-GetSpriteYByOffset(tgt))
	SetSpriteAngle(gun, angle#)
	SetSpriteAngle(turret, angle#)
	SetSpritePositionByOffset(turret, GetSpriteXByOffset(gun) + sin(angle#-180) * 5, GetSpriteYByOffset(gun) - cos(angle#-180) * 5)
endfunction


function ShowLaser(state)
	if state = 0
		SetSpriteVisible(laser, 0)
		exitfunction
	endif
	
	SetSpriteVisible(laser, 1)
	angle# = ATanFull(GetSpriteXByOffset(gun)-GetSpriteXByOffset(tgt), GetSpriteYByOffset(gun)-GetSpriteYByOffset(tgt))
	dist# = GetDistance(turret, tgt)
	SetSpriteAngle(laser, angle#)
	SetSpritePositionByOffset(laser, GetSpriteXByOffset(turret), GetSpriteYByOffset(turret))
	SetSpriteSize(laser, 0.5, dist#)
endfunction


function GetDistance(spr1, spr2)
	x# = GetSpriteXByOffset(spr1)-GetSpriteXByOffset(spr2)
	y# = GetSpriteYByOffset(spr1)-GetSpriteYByOffset(spr2)
	d# = sqrt(x#*x# + y#*y#)
endfunction d#


And my in game code:
Bullet (lightning) creation:
+ Code Snippet
if time > tower[t].lastShootTime + tower[t].shootRate
		tower[t].lastShootTime = time
		tower[t].preshoot = FALSE
		
		b as tBullet
		b.damage = tower[t].damage
		b.tower = t
		b.target = tower[t].target
		b.born = time
		b.life = 0.5
		b.style = tower[t].bulletstyle
		b.spr = CreateSprite(bulletImage[b.style])
		SetSpriteDepth(b.spr, DEPTH_BULLETS)
		dist# = GetDistanceSqr(turretX#, turretY#, enemy[tower[t].target].pos.x, enemy[tower[t].target].pos.y)
		SetSpriteOffset(b.spr, GetSpriteWidth(b.spr)*0.5, 0)
		SetSpriteSize(b.spr, 0, 0)
		SetSpriteAnimation(b.spr, 53, 128, 6)
		PlaySprite(b.spr, 25, 1)

		b.ang = ang#
		bullet.insert(b)
	endif

Bullet Update:
+ Code Snippet
			case BULLET_LIGHTNING
				tgt = bullet[b].target
				twr = bullet[b].tower
				enemySpr = enemy[tower[twr].target].col
				ang# = GetSpriteAngle(tower[twr].spr[1])
				turretX# = tower[twr].pos.x + sin(ang#+180)*9.5
				turretY# = tower[twr].pos.y - cos(ang#+180)*9.5
				dist# = GetDistance(turretX#, turretY#, GetSpriteX(enemySpr), GetSpriteY(enemySpr))
				
				SetSpritePositionByOffset(bullet[b].spr, turretX#, turretY#)
				SetSpriteSize(bullet[b].spr, device.w * 0.025, dist#)
				SetSpriteAngle(bullet[b].spr, ang#)

				if time > bullet[b].born + bullet[b].life
					ChangeEnemyHealth(tgt, bullet[b].damage)
					tower[twr].target = -1
					KillBullet(b)
					continue
				endif
			endcase


I'm sure it's something obvious but I've been staring at it for so long now that I've gone code blind.
Any help would be much appreciated.

Thanks
Posted: 29th Nov 2021 15:23
Solved by Virtual Nomad
It was this line in the bullet update code:
+ Code Snippet
dist# = GetDistance(turretX#, turretY#, GetSpriteX(enemySpr), GetSpriteY(enemySpr))

That should have been get the sprites offset positions.
So very obvious but it had become invisible to me!

I'll leave this post here because the "stand-alone" contains some useful code for anyone doing something similar.
Posted: 3rd Dec 2021 5:09
I late on this one but I did that exact same thing in my unfinished atom mash game

heres the function, it uses global type data but it can easily be edited to be generic, it will create the effect from startAtomID to endAtomID, or to the mouse if no endAtomID found, it scales the lightning effect to suit the distance and sets the correct angle, and yeah, I used offsets lol

+ Code Snippet
Function GUI_Game_DrawMergeOverlay(mouse_x#, mouse_y#, startAtomID, endAtomID)
	
	if GetSpriteExists(startAtomID)
		
		// highlight the start sprite
		start_x#=GetSpriteXByOffset(startAtomID)
		start_y#=GetSpriteYByOffset(startAtomID)

		SetSpritePositionByOffset(gGUIGame.spr_highlight_start, start_x#, start_y#)
		SetSpriteVisible(gGUIGame.spr_highlight_start, 1)

		SetSpriteColor(gGUIGame.spr_highlight_start, 255, 255, 255, 175)
		SetSpriteColor(gGUIGame.spr_highlight_end, 255, 255, 255, 175)
		SetSpriteColor(gGUIGame.spr_highlight_line, 255, 255, 255, 175)	
		

		// check for an end sprite
		if GetSpriteExists(endAtomID)
			
			end_x#=GetSpriteXByOffset(endAtomID)
			end_y#=GetSpriteYByOffset(endAtomID)
			mid_x#=start_x#+(end_x#-start_x#)/2
			mid_y#=start_y#+(end_y#-start_y#)/2
			
			line_distance# = Distance2D(start_x#, start_y#, mid_x#, mid_y#)
			line_angle# = ATanFull(start_x#-mid_x#, start_y#-mid_y#)
			
			SetSpritePositionByOffset(gGUIGame.spr_highlight_line, start_x#, start_y#)
			SetSpriteAngle(gGUIGame.spr_highlight_line, line_angle#)
			SetSpriteSize(gGUIGame.spr_highlight_line, 32, line_distance#*2)
			SetSpriteVisible(gGUIGame.spr_highlight_line, 1)

			SetSpritePositionByOffset(gGUIGame.spr_highlight_end, end_x#, end_y#)
			SetSpriteVisible(gGUIGame.spr_highlight_end, 1)
			
			Start_Atom_Type = GetSpriteGroup(startAtomID)
			End_Atom_Type = GetSpriteGroup(endAtomID)
			
			Select Collision_GetMergeStatus(Start_Atom_Type, End_Atom_Type)
				Case EVT_GOOD
					SetSpriteColor(gGUIGame.spr_highlight_start, 0, 255, 0, 175)
					SetSpriteColor(gGUIGame.spr_highlight_end, 0, 255, 0, 175)
					SetSpriteColor(gGUIGame.spr_highlight_line, 0, 255, 0, 175)
				EndCase
				Case EVT_UNKNOWN
					SetSpriteColor(gGUIGame.spr_highlight_start, 0, 0, 255, 175)
					SetSpriteColor(gGUIGame.spr_highlight_end, 0, 0, 255, 175)
					SetSpriteColor(gGUIGame.spr_highlight_line, 0, 0, 255, 175)
				EndCase
				Case EVT_BAD
					SetSpriteColor(gGUIGame.spr_highlight_start, 255, 0, 0, 175)
					SetSpriteColor(gGUIGame.spr_highlight_end, 255, 0, 0, 175)
					SetSpriteColor(gGUIGame.spr_highlight_line, 255, 0, 0, 175)
				EndCase
			EndSelect
	
		else
			// no end sprite, draw to the mouse
			mid_x#=mouse_x#+(start_x#-mouse_x#)/2
			mid_y#=mouse_y#+(start_y#-mouse_y#)/2	
			line_distance# = Distance2D(start_x#, start_y#, mid_x#, mid_y#)
			line_angle# = ATanFull(start_x#-mid_x#, start_y#-mid_y#)
			
			SetSpritePositionByOffset(gGUIGame.spr_highlight_line, start_x#, start_y#)
			SetSpriteAngle(gGUIGame.spr_highlight_line, line_angle#)
			SetSpriteSize(gGUIGame.spr_highlight_line, 32, line_distance#*2)
			SetSpriteVisible(gGUIGame.spr_highlight_line, 1)
			SetSpritePositionByOffset(gGUIGame.spr_highlight_end, mouse_x#, mouse_y#)
			
			SetSpriteVisible(gGUIGame.spr_highlight_start, 1)
			SetSpriteVisible(gGUIGame.spr_highlight_end, 0)
			SetSpriteVisible(gGUIGame.spr_highlight_line, 1)
			
			SetSpriteColor(gGUIGame.spr_highlight_start, 255, 255, 0, 175)
			SetSpriteColor(gGUIGame.spr_highlight_end, 255, 255, 0, 175)
			SetSpriteColor(gGUIGame.spr_highlight_line, 255, 255, 0, 175)
		endif
	else
		SetSpriteVisible(gGUIGame.spr_highlight_line, 0)
		SetSpriteVisible(gGUIGame.spr_highlight_end, 0)
		SetSpriteVisible(gGUIGame.spr_highlight_start, 0)	
	endif
	
EndFunction