tjcioffe

About onewinter

My name is TJ Cioffe and I’m from Brooklyn NY, where I currently live with my wife and our 3(!) cats. I spent the first 15 years of my career in the IT space as a sysadmin, db admin, web developer, and general jack-of-all-trades “IT guy”. As much as I loved that world, I realized that I needed to pivot to a new career that would allow me to use some of those skills while also doing something that I loved. As such, I enrolled in the MA program for Game Development at AAU. I don’t yet know what I want to focus on in my degree, but am excited to learn more and nail down an area of specialization as I continue! Avid Arsenal, Giants, and Knicks fan. Cat owner.

Projectile Arcing in Unity with Animation Curves

I recently had to figure out how to move a projectile in an Arc for a project I’m working on and found that a Google search was harder than expected, so I’m writing this up in that hopes that it might help someone else! For starters, take a look at this post on how to do it in 2D, as well as some explanation on the math behind it. For our purposes, we’re going to let Unity handle calculating the arc by simply using an Animation Curve. (Kind of hilariously, I spent part of the past weekend learning Animation Curves in Unity, only to have it be the subject of my next Maya class come Monday morning. Hindsight!)

This is the code I’m using, which is hyper-specific to my project, but we can break it down in principle. (I’ll cover ScriptableObject TypeObjects in a later post, but that’s what’s going on here; Projectile is a MonoBehaviour and the class below is a ScriptableObject)

  • Line 7: CurrentTime += Time.deltaTime in Update(). Duration is how long the projectile should take from firing to reach its target. linearT calculates the ratio from 0 to 1 of how close to done we are, given a desired Duration.
  • Line 9: PositionXZ() is an extension function I wrote that returns a Vector3 with its Y value set to 0. This function handles moving the projectile towards the target on the X and Z axes, using Lerp and linearT to interpolate smoothly.
  • Line 11: does the same thing but only for the Y axis. This ensures that we end up at the correct height for the target, in case the start and end Y positions are different.
  • Line 13: uses the same 0 to 1 value in linearT to evaluate the animation curve and return a height offset value. This is multiplied by curveMaxHeight to determine the effective height at the top of the parabola.
  • Line 15: adds the Lerped Y to the Offset Y to get the new effective Y. (If we’re Lerping from 0y to 0y, baseY will be 0y throughout, so the arc offset will determine the Y value alone.)

And here’s the animation curve stored in the curveHeight field:

You’ll want to manually clamp the points on the X axis at 0 and 1 to a value of 0. This ensures that at the start and end, no height is added to the projectile. Add a key point at 0.55 and set its value to .95. Set the Start and End tangents to linear; you want the projectile to shoot up towards the peak and come down towards the target quickly. In the middle, you can keep the point at Auto; grab the tangent handle and turn it clockwise so that the right hand side of the parabola is as close to a 45 degree angle as you can get it, which should push the peak to touching 1 on the Y axis.

This system works beautifully, because the offset for the mortar in the Animation Curve matches what you expect it to look like in the game, which I find makes it easier to wrap your head around how it works. You can play around with the tangents if you want to extend that hang at the top, but this works pretty well as is.

Looks pretty good, and no tricky math required… it should also be adaptable for other projectiles like rockets or arrows if you flatten out the Animation Curve. Try it out!

Edit 2022/08/20: I randomly stumbled across https://blog.terresquall.com/2019/11/coding-projectiles-for-your-tower-defense-game-part-2/ and thought it was a great explanation of the same concept; so for further reading, check it out.

2022-08-20T05:04:35-04:00July 21st, 2022|Categories: General|Tags: , , , , |0 Comments

More Portfolio Updates

Filled out a few more pages on the portfolio so it’s fully complete. Check ’em out!

The Adventures of Robo Boy in Cloud City, an adorable platformer written in Construct that will challenge you!


Odds & Evens: 2048 Plus, my first mobile game that you can still download from the Google Play Store!


Zap City, a top-down 2D game where you must use your chain lightning ability to defeat enemies and solve puzzles as you try to escape the city.


2022-07-08T14:39:45-04:00July 8th, 2022|Categories: General|Tags: |0 Comments

New Site Design!

Spent the last few days working on a full overhaul of the site using the Avada theme… Really enjoyed all the different ways to customize everything (and I barely scratched the surface of what’s possible–I still have classwork to do, after all!)  Realized that having a shiny site that I’m proud of and that’s easy to add content to will make me more likely to update this regularly.  So, yay.  Be back soon to continue filling in those portfolio projects! 🙃

2022-06-28T10:20:16-04:00June 28th, 2022|Categories: General|Tags: |0 Comments

Portfolio Updates

Added Portfolio post types to my WordPress setup and started filling in some work over on the Portfolio page. Check it out!

Some highlights:

Spiced Pumpking, a Monopoly-meets-Spaceteam-esque game that has you battling for supremacy of the Pumpkin Spiced Latte market.


A Sunset Rendezvous, a simple 2D top-down game in the style of the original Zelda.


The Great Hunt, a prehistoric dice war game that could be played by hunters on the go.


My Drawing Bootcamp Sketches, where you can see me do my best to draw (I definitely improved a lot by the end!).


I’ll be filling in the rest of the current projects in the upcoming days and will update here once it’s all done. I challenged myself to post once per module during this summer semester, so that’s twice a week! So, more to come soon. Cheers!

2022-06-28T10:21:33-04:00June 26th, 2022|Categories: General|Tags: , |0 Comments

GitHub & Itch.io Pages

It’s always so bizarre to open up WordPress after a long time away and see how much has changed (even moreso when you think about the fact that I’ve been using WordPress in some way or another since before it was even called that.)

Anywho, I’ve challenged myself to spend some time in between grad school semesters writing about the projects I worked on this semester and some of the stuff I’ll be working on in the future. We’ll start here with links to my GitHub and Itch.io pages, where I published the three projects I’ll be talking about in future posts.

GitHub

Itch.io

Even though this code is nothing special, I’m publishing it alongside the actual playable versions in the hope that something in there might be useful to someone down the line; in addition, I feel like it’s healthy to put your code out into the world whenever you can, inviting discussion and criticism with the eventual goal of learning and growing from the experience.

Ta for now!

2022-06-28T10:21:18-04:00June 1st, 2022|Categories: General|Tags: , , , , |0 Comments

Withings-Sync Python/Powershell Script w/ Discord Webhook Notifications

I recently deployed https://github.com/jaroslawhartman/withings-sync to sync my Withings scale to my Garmin account. Here’s a quick Powershell script I whipped up that runs via Scheduled Tasks on Windows and uses a Discord Webhook to notify you of its progress:

# function adapted from https://stackoverflow.com/posts/42995301/revisions
Function Execute-Command ($commandTitle, $commandPath, $commandArguments)
{
Try {
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = $commandPath
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = $commandArguments
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
[pscustomobject]@{
commandTitle = $commandTitle
stdout = $p.StandardOutput.ReadToEnd()
}
$p.WaitForExit()
}
Catch {
exit
}
}
# call this with garmin username & password to sync from withings
function withings-sync( $username, $password )
{
# setup vars
$hoursToPause = 2
$fromDate = Get-Date
$loop = $true
$countOfTries = 0
$maxTries = 10
$user = $username
$pwd = $password
$wsPath = "C:\python38\scripts\withings-sync.exe"
# discord setup
$discordBot = "Withings -> Garmin Sync"
$hookUrl = "https://discord.com/api/webhooks/xxxx"
$content = "{0:HH:mm:ss}: Garmin upload beginning for $user." -f ( (Get-Date) )
$section = New-DiscordSection Title "Info" Description $content Color LightGrey
# send discord update on start
Write-Host $content
Send-DiscordMessage webHookUrl $hookUrl Sections $section AvatarName $discordBot
do
{
# only retry $maxTries times
if($countOfTries -lt $maxTries)
{
# create args, then try withings-sync upload and capture output
$args = ("–garmin-username ${user} –garmin-password ${pwd} –fromdate {0:yyyy-MM-dd}" -f $fromDate).ToString()
$process = ExecuteCommand commandTitle "Withings->Garmin Sync" commandPath $wsPath commandArguments $args
$outputText = $process.stdout
Write-Host $outputText
# if upload worked, break loops
if( $outputText.Contains("Fit file uploaded to Garmin Connect") )
{
$content = "{0:HH:mm:ss}: Garmin upload successful for $user." -f ( (Get-Date) )
$section = New-DiscordSection Title "Info" Description $content Color Green
$loop = $false
}
# if no measurements, wait and try again later
elseif( $outputText.Contains("No measurements to upload for date or period specified") )
{
$content = "{0:HH:mm:ss}: No Withings measurements found for $user; sleeping $hoursToPause hour(s) and trying again." -f ( (Get-Date) )
$section = New-DiscordSection Title "Alert" Description $content Color Yellow
}
# if withings refresh failed
elseif( $outputText.Contains("withings – ERROR") )
{
$content = "{0:HH:mm:ss}: Withings refresh failed for $user; sleeping $hoursToPause hour(s) and trying again." -f ( (Get-Date) )
$section = New-DiscordSection Title "Alert" Description $content Color Red
}
# if garmin upload failed
else
{
$content = "{0:HH:mm:ss}: Garmin upload failed for $user; sleeping $hoursToPause hour(s) and trying again." -f ( (Get-Date) )
$section = New-DiscordSection Title "Alert" Description $content Color Red
}
# send discord update
Write-Host $content
Send-DiscordMessage webHookUrl $hookUrl Sections $section AvatarName $discordBot
# pause for $countOfTries hour(s) and try again
$countOfTries = $countOfTries + 1
if($loop) { Start-Sleep ( $hoursToPause * 60 * 60 ) }
}
# after #maxTries failures, send discord update and exit the loop
else
{
$content = "{0:HH:mm:ss}: Garmin upload failed $maxTries times, aborting." -f ( (Get-Date) )
$section = New-DiscordSection Title "Alert" Description $content Color Red
Write-Host $content
Send-DiscordMessage webHookUrl $hookUrl Sections $section AvatarName $discordBot
$loop = $false
}
}
while ($loop -eq $true)
}

Install the PSDiscord powershell module. Set $hookUrl with your Discord Webhook URL. Setup your path to the Python withings-sync executable in the $wsPath variable, then call the withings-sync function from Powershell after initializing your Withings token with withings-sync manually, as per the github instructions (pass your Garmin credentials as the $username and $password parameters). The script will auto-retry up to $maxTries times every $hoursToPause.

Edited 2021-09-21: removed some code from the Execute-Command function that could cause a deadlock when Garmin spits out its 403 error and changed the order of the if/else statements slightly. Cheers!

2022-06-28T17:49:01-04:00August 13th, 2021|Categories: General|Tags: , , , , |0 Comments

More Regular Updates

Hi again!

As part of an assignment for the Master of Arts degree I’m currently pursuing at the Academy of Art University in San Francisco, I took a look around this site and did some mild clean-up. Going forward, I’ll be adding new pages as I complete projects that will improve my portfolio. I’m also going to endeavor to start posting here a few times a week, talking about what I’m working on or currently playing–plus I’m sure some random musings or venting.

See you soon!

2022-06-27T08:09:45-04:00August 3rd, 2021|Categories: General|Tags: |0 Comments

Odds & Evens: 2048 Plus v2.08 Released

appstorebutton-white google-play

Odds & Evens: 2048 Plus v2.08 is out now on the Google Play Store and Apple App Store!

Changes in this release:

  • Redo Main Menu and Game Options to make it easier to set up a new game
  • Remove Video button, move Undo button & Restart Game buttons
  • Add About menu with current version number and credits
  • Refresh Play/App Store screenshots

Follow Odds & Evens: 2048 Plus on Facebook!

2021-08-03T14:01:45-04:00December 20th, 2016|Categories: General|Tags: , |0 Comments

onewinter network launched

Hello there!

This will be the new incarnation of the onewinter network, the place where I offer my 3d printing services and list the mobile games that I’ve created.

This blog will hopefully be updated with things I learn while working in Unity3d and with my two 3D printers in the future, so that others using the same technology solutions can learn from my struggles and successes.

More to come soon!

2021-08-03T14:01:34-04:00December 13th, 2016|Categories: General|Tags: |0 Comments

About My Work

Phasellus non ante ac dui sagittis volutpat. Curabitur a quam nisl. Nam est elit, congue et quam id, laoreet consequat erat. Aenean porta placerat efficitur. Vestibulum et dictum massa, ac finibus turpis.

Recent Works

Recent Posts