2013-09-26 5 views
20

Интересно, есть ли инструмент, который можно было бы использовать для простого создания сложных физических тел в SpriteKit. Я хотел бы иметь физические тела с многоугольными формами. SpriteKit позволяет создавать такие органы с этим методом:SKPhysicsBody от SpriteKit с помощью вспомогательного инструмента многоугольника

+ (SKPhysicsBody *)bodyWithPolygonFromPath:(CGPathRef)path 

К сожалению, это отнимает много времени задача создания таких путей вручную, и это может быть проблематичным при тестировании. Существует приложение SpriteHelper, которое позволяет вам определять форму тела в удобном визуальном редакторе, но это приложение не может экспортировать пути, которые можно использовать здесь. Он был сделан для cocos2d, и он делает много вещей, таких как упаковка текстур и т. Д., Которые мне не нужны, и я не могу использовать с SpriteKit. Кто-нибудь знает решение, которое позволит легко определить CGPath или, возможно, автоматически сгенерировать их из png-изображений с альфа-каналом? Хотя функция автогенерации по моему опыту нуждается в оптимизации, потому что формы тела должны быть максимально простыми, если текстуры могут иметь более сложные формы.

+0

PhysicsEditor получит обновление Kit Sprite в ближайшее время. – LearnCocos2D

+0

@ LearnCocos2D Я обязательно куплю его, когда будет добавлена ​​поддержка SpriteKit. Я надеюсь, что будет возможность экспортировать формы конфликтов в формате кода Objective-c (декларация CGPath или что-то подобное). Экспорт в пользовательский формат файла, читаемый внешней библиотекой, не является тем, что я ищу. – Darrarski

+0

Экспорт кода - это действительно плохая идея, потому что он легко ломается, хорошие инструменты всегда записывают в пользовательский формат файла (обычно в виде xml), а затем предоставляют код загрузчика – LearnCocos2D

ответ

64

Я ищу то же самое, что и оказалось, для этого я сделал небольшое веб-приложение.

SKPhysicsBody Путь Генератор

как действие в примере: enter image description here

Update 2015-02-13: сценарий

<!DOCTYPE html> 
 
<html> 
 
    <head> 
 
     <meta charset="UTF-8"> 
 
     <title>SpriteKit Tools - SKPhysicsBody Path Generator</title> 
 
     <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"> 
 

 
     <style> 
 
      /* disable responsive */ 
 
      .container { 
 
       max-width: none; 
 
       width: 970px; 
 
      } 
 
      #sprite { 
 
       background-color: #eee; 
 
       position: absolute; 
 
      } 
 
      #path { 
 
       cursor: crosshair; 
 
       opacity: 0.5; 
 
      } 
 
     </style> 
 

 
    </head> 
 
    <body> 
 
     <div class="container"> 
 
      <h1>SKPhysicsBody Path Generator</h1> 
 
      <p class="lead">Want to use [SKPhysicsBody bodyWithPolygonFromPath:path] easier way like me? Here with a small helper for easier path drawing, hope it help others too.</p> 
 
      <div class="row"> 
 
       <div class="col-md-6"> 
 
        <h5>Basic Instruction</h5> 
 
        <ol> 
 
         <li><small>Drag and drop the sprite image into drop zone.</small></li> 
 
         <li><small>Start drawing path by clicking on coordinates.</small></li> 
 
        </ol> 
 
       </div> 
 
       <div class="col-md-6"> 
 
        <h5>Some Rules/Known Issue</h5> 
 
        <ul> 
 
         <li><small>Path need to be as a convex polygonal path with counterclockwise winding and no self intersections. The points are specified relative to the owning node’s origin. <a href="https://developer.apple.com/documentation/spritekit/skphysicsbody/1520379-bodywithpolygonfrompath" target="_blank">(documentation link)</a></small></li> 
 
         <li><small>Please use Chrome for best compatibility as I have not tested on other browsers.</small></li> 
 
        </ul> 
 
       </div> 
 
      </div> 
 

 

 
      <hr> 
 

 
      <div class="btn-group"> 
 
       <button class="btn btn-primary" type="button" onclick="resetShape()">Reset Shape</button> 
 
       <button class="btn btn-primary" type="button" onclick="location.reload()">Reset All</button> 
 
      </div> 
 
      <input type="checkbox" onclick="toggleRetinaMode()" id="retinaCheckbox" checked> Retina? (please check before declaring path) 
 
      <br><br> 
 

 
      <canvas id="sprite" width="940" height="100"></canvas> 
 
      <canvas id="path" width="0" height="100"></canvas> 
 

 
      <p class="text-muted"><small>X:<span id="tooltipX">0</span> Y:<span id="tooltipY">0</span></small></p> 
 
      <br> 
 

 
      <h5>Output</h5> 
 
<pre> 
 
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:@"<span id="codeImgName">img</span>"]; 
 

 
CGFloat offsetX = sprite.frame.size.width * sprite.anchorPoint.x; 
 
CGFloat offsetY = sprite.frame.size.height * sprite.anchorPoint.y; 
 

 
CGMutablePathRef path = CGPathCreateMutable(); 
 

 
<span id="codeCGPath"></span> 
 
CGPathCloseSubpath(path); 
 

 
sprite.physicsBody = [SKPhysicsBody bodyWithPolygonFromPath:path]; 
 
</pre> 
 

 
     </div> 
 

 
     <script> 
 
// reference from http://davidwalsh.name/resize-image-canvas 
 

 
var spriteCanvas = document.getElementById('sprite'); 
 
var spriteContext = spriteCanvas.getContext('2d'); 
 
spriteContext.fillText('Drop Sprite Image Here', 400, 50); 
 

 
var pathCanvas = document.getElementById('path'); 
 
var pathContext = pathCanvas.getContext('2d'); 
 

 
function render(src){ 
 
    var image = new Image(); 
 
    image.onload = function(){ 
 
     spriteContext.clearRect(0, 0, spriteCanvas.width, spriteCanvas.height); 
 
     spriteCanvas.width = image.width; 
 
     spriteCanvas.height = image.height; 
 
     spriteContext.drawImage(image, 0, 0, image.width, image.height); 
 

 
     pathContext.clearRect(0, 0, pathCanvas.width, pathCanvas.height); 
 
     pathCanvas.width = image.width; 
 
     pathCanvas.height = image.height; 
 
    }; 
 
    image.src = src; 
 
} 
 

 
function loadImage(src){ 
 

 
    if(!src.type.match(/image.*/)){ 
 
     console.log('Dropped file is not image format'); 
 
     return; 
 
    } 
 

 
    var reader = new FileReader(); 
 
    reader.onload = function(e){ 
 
     render(e.target.result); 
 
    }; 
 
    reader.readAsDataURL(src); 
 

 
    var fileName = src.name; 
 
    var codeImgName = document.getElementById('codeImgName'); 
 
    codeImgName.innerHTML = fileName; 
 
} 
 

 
spriteCanvas.addEventListener('dragover', function(e){ 
 
    e.preventDefault(); 
 
}, true); 
 

 
spriteCanvas.addEventListener('drop', function(e){ 
 
    e.preventDefault(); 
 
    loadImage(e.dataTransfer.files[0]); 
 
}, true); 
 

 

 
var retinaMode = true; 
 
function toggleRetinaMode(){ 
 
    var status = document.getElementById('retinaCheckbox'); 
 

 
    retinaMode = status.checked ? true : false; 
 
} 
 

 

 

 
var actualX = 0; 
 
var actualY = 0; 
 
var displayX = document.getElementById('tooltipX'); 
 
var displayY = document.getElementById('tooltipY'); 
 

 
pathCanvas.onmousemove = function(e){ 
 
    actualX = e.pageX - this.offsetLeft; 
 
    actualY = e.pageY - this.offsetTop; 
 
    displayX.innerHTML = retinaMode ? Math.floor(actualX/2) : actualX; 
 
    displayY.innerHTML = retinaMode ? Math.floor((spriteCanvas.height - actualY - 1)/2) : spriteCanvas.height - actualY - 1; 
 
} 
 

 
var pathArray = new Array(); 
 
pathCanvas.onclick = function(e){ 
 
    var coor = { 
 
     actualX: actualX, 
 
     actualY: actualY, 
 
     displayX: displayX.innerHTML, 
 
     displayY: displayY.innerHTML, 
 
    }; 
 
    pathArray.push(coor); 
 
    refreshShape(pathArray); 
 
} 
 

 
var codeCGPath = document.getElementById('codeCGPath'); 
 
function refreshShape(pathArray){ 
 

 
    pathContext.clearRect(0, 0, pathCanvas.width, pathCanvas.height); 
 

 
    pathContext.beginPath(); 
 

 
    for(var i in pathArray){ 
 
     if(i == 0) { 
 
      pathContext.moveTo(pathArray[i].actualX, pathArray[i].actualY); 
 
      codeCGPath.innerHTML = 'CGPathMoveToPoint(path, NULL, '+pathArray[i].displayX+' - offsetX, '+pathArray[i].displayY+' - offsetY);<br>'; 
 
      continue; 
 
     } 
 
     pathContext.lineTo(pathArray[i].actualX, pathArray[i].actualY); 
 
     codeCGPath.innerHTML += 'CGPathAddLineToPoint(path, NULL, '+pathArray[i].displayX+' - offsetX, '+pathArray[i].displayY+' - offsetY);<br>'; 
 
    } 
 

 
    pathContext.closePath(); 
 
    pathContext.lineWidth = 1; 
 
    pathContext.strokeStyle = 'blue'; 
 
    pathContext.stroke(); 
 
    pathContext.fillStyle = 'blue'; 
 
    pathContext.fill(); 
 
} 
 

 
function resetShape(){ 
 
    pathArray = new Array(); 
 
    codeCGPath.innerHTML = null; 
 
    pathContext.clearRect(0, 0, pathCanvas.width, pathCanvas.height); 
 
} 
 
     </script> 
 
    </body> 
 
</html>

+1

Да! Это именно то, что я искал! Я думаю, что многие люди согласны с тем, что то, что вы сделали, стоит дальнейшего развития. Я там где-нибудь мог писать запросы на функцию? – Darrarski

+1

@ Darrarski, да. Просто оставьте это в разделе комментариев ниже. Я знаю некоторые функции при кодировании, но я временно оставляю сложный материал, который будет заполняться в будущем, и получить базовый уровень и работать на время (потому что я сейчас на пути развития игры). Во всяком случае, я попрошу вас уйти в раздел комментариев, а другие могут прочитать, прежде чем публиковать то же самое. :) – DazChong

+1

Это одна из самых полезных вещей, которые я видел. Отличная работа. – Grenter

1

Удивительный маленький веб-приложение, с помощью DazChong , И canot ждет обновления PhysicsEditor !!

Это one также в развитии

Вы можете загрузить его в альфа-стадии here

enter image description here

+0

Это потрясающе! Спасибо, что поделился. Возможно, название приложения должно включать «SpriteKit» для более легкой поисковой посадки. – DazChong

+0

@ DazChong да имеет большой потенциал.Мне нравится ваше веб-приложение, стыд SpriteKit позволяет только 12 точек для пути. Если вы не знаете, есть и этот, но $$$$ http://www.paintcodeapp.com – DogCoffee

+0

проблема с 12 пунктами для пути даже хуже, чем потому, что она должна состоять в основном из 12 точек, соединенных прямыми линиями. Я попытался использовать фигуры, которые имели 12 очков, но использовали кривые Безье между ними и получили сообщение типа «использование более 300 точек» или любого такого гигантского числа. Apple сделала хромую работу с этим и, кстати, SpriteKit - это мешок ошибок: я сообщил о по меньшей мере 20 ошибках, которые я обнаружил через неделю, используя это. – SpaceDog

8

Я создал редактор и загрузчик классов для создания сложных SKPhysicsBodies и импортировать их в свой код. Это позволяет отслеживать вокруг вашего спрайта, добавлять несколько тел и экспортировать все в довольно приятный интерфейс. Проверьте SKImport here и editor.

Screencast

5

Я знаю, что это немного поздно, но я только что создал классный инструмент для этой цели, который автоматически создает путь вокруг спрайта (так вам не нужно вручную вручную нажимать на них), а затем вы можете настроить различные параметры, чтобы лучше соответствовать вашим требованиям. Инструмент также выводит программный код Objective C и Swift для добавления пути к физическому телу спрайта. Надеюсь, что это полезно для некоторых людей.Спасибо:

http://www.radicalphase.com/pathgen/

+0

слишком плохо ... ссылка мертва –

+0

извините доменное имя истекло - инструмент снова вернулся! :) –

+0

Новое обновление: теперь включает режим выпуклой силы (включен по умолчанию), чтобы обеспечить 100% совместимость с физическими телами SpriteKit, а также уменьшить количество очков - наслаждайтесь! :) –

4

Вот оригинальный сценарий (от DazChong), адаптированный для Swift

SKPhysicsBody Путь Генератор Swift Версия

<!DOCTYPE html> 
 
<html> 
 
<head> 
 
    <meta charset="UTF-8"> 
 
    <title>SpriteKit Tools - SKPhysicsBody Path Generator (Swift version </title> 
 
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"> 
 

 
    <style> 
 
     /* disable responsive */ 
 
     .container { 
 
      max-width: none; 
 
      width: 970px; 
 
     } 
 

 
      #sprite { 
 
       background-color: #eee; 
 
       position: absolute; 
 
      } 
 
      #path { 
 
       cursor: crosshair; 
 
       opacity: 0.5; 
 
      } 
 
     </style> 
 

 
    </head> 
 
    <body> 
 
     <div class="container"> 
 
      <h1>SKPhysicsBody Path Generator</h1> 
 
      <p class="lead">Want to use SKPhysicsBody(polygonFromPath: path) easier way like me? Here with a small helper for easier path drawing, hope it help others too.</p> 
 
      <div class="row"> 
 
       <div class="col-md-6"> 
 
        <h5>Basic Instruction</h5> 
 
        <ol> 
 
         <li><small>Drag and drop the sprite image into drop zone.</small></li> 
 
         <li><small>Start drawing path by clicking on coordinates.</small></li> 
 
        </ol> 
 
       </div> 
 
       <div class="col-md-6"> 
 
        <h5>Some Rules/Known Issue</h5> 
 
        <ul> 
 
         <li><small>Path need to be as a convex polygonal path with counterclockwise winding and no self intersections. The points are specified relative to the owning node’s origin. <a href="https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKPhysicsBody_Ref/Reference/Reference.html#//apple_ref/occ/clm/SKPhysicsBody/bodyWithPolygonFromPath:" target="_blank">(documentation link)</a></small></li> 
 
         <li><small>Please use Chrome for best compatibility as I have not tested on other browsers.</small></li> 
 
        </ul> 
 
       </div> 
 
      </div> 
 

 

 
      <hr> 
 

 
      <div class="btn-group"> 
 
       <button class="btn btn-primary" type="button" onclick="resetShape()">Reset Shape</button> 
 
       <button class="btn btn-primary" type="button" onclick="location.reload()">Reset All</button> 
 
      </div> 
 
      <input type="checkbox" onclick="toggleRetinaMode()" id="retinaCheckbox" checked> Retina? (please check before declaring path) 
 
      <br><br> 
 

 
      <canvas id="sprite" width="940" height="100"></canvas> 
 
      <canvas id="path" width="0" height="100"></canvas> 
 

 
      <p class="text-muted"><small>X:<span id="tooltipX">0</span> Y:<span id="tooltipY">0</span></small></p> 
 
      <br> 
 

 
      <h5>Output</h5> 
 
<pre> 
 
let sprite = SKSpriteNode(imageNamed: "codeImgName") 
 

 
let offsetX = sprite.size.width * sprite.anchorPoint.x 
 
let offsetY = sprite.size.height * sprite.anchorPoint.y 
 

 
let path = CGPathCreateMutable() 
 

 
<span id="codeCGPath"></span> 
 
CGPathCloseSubpath(path) 
 

 
sprite.physicsBody = SKPhysicsBody(polygonFromPath: path) 
 
</pre> 
 

 
     </div> 
 

 
     <script> 
 
// reference from http://davidwalsh.name/resize-image-canvas 
 

 
var spriteCanvas = document.getElementById('sprite'); 
 
var spriteContext = spriteCanvas.getContext('2d'); 
 
spriteContext.fillText('Drop Sprite Image Here', 400, 50); 
 

 
var pathCanvas = document.getElementById('path'); 
 
var pathContext = pathCanvas.getContext('2d'); 
 

 
function render(src){ 
 
    var image = new Image(); 
 
    image.onload = function(){ 
 
     spriteContext.clearRect(0, 0, spriteCanvas.width, spriteCanvas.height); 
 
     spriteCanvas.width = image.width; 
 
     spriteCanvas.height = image.height; 
 
     spriteContext.drawImage(image, 0, 0, image.width, image.height); 
 

 
     pathContext.clearRect(0, 0, pathCanvas.width, pathCanvas.height); 
 
     pathCanvas.width = image.width; 
 
     pathCanvas.height = image.height; 
 
    }; 
 
    image.src = src; 
 
} 
 

 
function loadImage(src){ 
 

 
    if(!src.type.match(/image.*/)){ 
 
     console.log('Dropped file is not image format'); 
 
     return; 
 
    } 
 

 
    var reader = new FileReader(); 
 
    reader.onload = function(e){ 
 
     render(e.target.result); 
 
    }; 
 
    reader.readAsDataURL(src); 
 

 
    var fileName = src.name; 
 
    var codeImgName = document.getElementById('codeImgName'); 
 
    codeImgName.innerHTML = fileName; 
 
} 
 

 
spriteCanvas.addEventListener('dragover', function(e){ 
 
    e.preventDefault(); 
 
}, true); 
 

 
spriteCanvas.addEventListener('drop', function(e){ 
 
    e.preventDefault(); 
 
    loadImage(e.dataTransfer.files[0]); 
 
}, true); 
 

 

 
var retinaMode = true; 
 
function toggleRetinaMode(){ 
 
    var status = document.getElementById('retinaCheckbox'); 
 

 
    retinaMode = status.checked ? true : false; 
 
} 
 

 

 

 
var actualX = 0; 
 
var actualY = 0; 
 
var displayX = document.getElementById('tooltipX'); 
 
var displayY = document.getElementById('tooltipY'); 
 

 
pathCanvas.onmousemove = function(e){ 
 
    actualX = e.pageX - this.offsetLeft; 
 
    actualY = e.pageY - this.offsetTop; 
 
    displayX.innerHTML = retinaMode ? Math.floor(actualX/2) : actualX; 
 
    displayY.innerHTML = retinaMode ? Math.floor((spriteCanvas.height - actualY - 1)/2) : spriteCanvas.height - actualY - 1; 
 
} 
 

 
var pathArray = new Array(); 
 
pathCanvas.onclick = function(e){ 
 
    var coor = { 
 
     actualX: actualX, 
 
     actualY: actualY, 
 
     displayX: displayX.innerHTML, 
 
     displayY: displayY.innerHTML, 
 
    }; 
 
    pathArray.push(coor); 
 
    refreshShape(pathArray); 
 
} 
 

 
var codeCGPath = document.getElementById('codeCGPath'); 
 
function refreshShape(pathArray){ 
 

 
    pathContext.clearRect(0, 0, pathCanvas.width, pathCanvas.height); 
 

 
    pathContext.beginPath(); 
 

 
    for(var i in pathArray){ 
 
     if(i == 0) { 
 
      pathContext.moveTo(pathArray[i].actualX, pathArray[i].actualY); 
 
      codeCGPath.innerHTML = 'CGPathMoveToPoint(path, nil, '+pathArray[i].displayX+' - offsetX, '+pathArray[i].displayY+' - offsetY)<br>'; 
 
      continue; 
 
     } 
 
     pathContext.lineTo(pathArray[i].actualX, pathArray[i].actualY); 
 
     codeCGPath.innerHTML += 'CGPathAddLineToPoint(path, nil, '+pathArray[i].displayX+' - offsetX, '+pathArray[i].displayY+' - offsetY)<br>'; 
 
    } 
 

 
    pathContext.closePath(); 
 
    pathContext.lineWidth = 1; 
 
    pathContext.strokeStyle = 'blue'; 
 
    pathContext.stroke(); 
 
    pathContext.fillStyle = 'blue'; 
 
    pathContext.fill(); 
 
} 
 

 
function resetShape(){ 
 
    pathArray = new Array(); 
 
    codeCGPath.innerHTML = null; 
 
    pathContext.clearRect(0, 0, pathCanvas.width, pathCanvas.height); 
 
} 
 
     </script> 
 
    </body> 
 
</html>

0

Вы можете просто сделайте это сейчас, чтобы ген Скорость физика тело из PNG вашего спрайта:

SKSpriteNode *yourPhysicsSprite = [SKSpriteNode spriteNodeWithImageNamed:@"yourPNG"]; 
yourPhysicsSprite.physicsBody = [SKPhysicsBody bodyWithTexture:yourPhysicsSprite.texture alphaThreshold:0.0f size:yourPhysicsSprite.texture.size]; 

Менее точные и, возможно, более дорогостоящий, чем делать вручную, но работает отлично.

+0

Не удалось в SpriteKit, когда я задал вопрос. Теперь это возможно, но не очень эффективно. – Darrarski

+0

Возможно ли сделать это многоугольное поколение изнутри XCode сейчас? Если да, то где это? У меня проблемы с этим. –

+0

Просто, чтобы люди знали, в iOS9 есть огромная ошибка, которая мешает вам использовать текстуры для создания точных физических тел. Странно это работало в iOS8 и работает в iOS10, но массовые проблемы в iOS9, по-прежнему не фиксированные на сегодняшний день (все, хотя есть некоторые * не большие * обходные пути). – Abhi

1

Это адаптация ответ Xelt в Swift 3.

<!DOCTYPE html> 
 
<html> 
 
<head> 
 
    <meta charset="UTF-8"> 
 
    <title>SpriteKit Tools - SKPhysicsBody Path Generator (Swift version </title> 
 
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"> 
 

 
    <style> 
 
     /* disable responsive */ 
 
     .container { 
 
      max-width: none; 
 
      width: 970px; 
 
     } 
 

 
      #sprite { 
 
       background-color: #eee; 
 
       position: absolute; 
 
      } 
 
      #path { 
 
       cursor: crosshair; 
 
       opacity: 0.5; 
 
      } 
 
     </style> 
 

 
    </head> 
 
    <body> 
 
     <div class="container"> 
 
      <h1>SKPhysicsBody Path Generator</h1> 
 
      <p class="lead">Want to use SKPhysicsBody(polygonFromPath: path) easier way like me? Here with a small helper for easier path drawing, hope it help others too.</p> 
 
      <div class="row"> 
 
       <div class="col-md-6"> 
 
        <h5>Basic Instruction</h5> 
 
        <ol> 
 
         <li><small>Drag and drop the sprite image into drop zone.</small></li> 
 
         <li><small>Start drawing path by clicking on coordinates.</small></li> 
 
        </ol> 
 
       </div> 
 
       <div class="col-md-6"> 
 
        <h5>Some Rules/Known Issue</h5> 
 
        <ul> 
 
         <li><small>Path need to be as a convex polygonal path with counterclockwise winding and no self intersections. The points are specified relative to the owning node’s origin. <a href="https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKPhysicsBody_Ref/Reference/Reference.html#//apple_ref/occ/clm/SKPhysicsBody/bodyWithPolygonFromPath:" target="_blank">(documentation link)</a></small></li> 
 
         <li><small>Please use Chrome for best compatibility as I have not tested on other browsers.</small></li> 
 
        </ul> 
 
       </div> 
 
      </div> 
 

 

 
      <hr> 
 

 
      <div class="btn-group"> 
 
       <button class="btn btn-primary" type="button" onclick="resetShape()">Reset Shape</button> 
 
       <button class="btn btn-primary" type="button" onclick="location.reload()">Reset All</button> 
 
      </div> 
 
      <input type="checkbox" onclick="toggleRetinaMode()" id="retinaCheckbox" checked> Retina? (please check before declaring path) 
 
      <br><br> 
 

 
      <canvas id="sprite" width="940" height="100"></canvas> 
 
      <canvas id="path" width="0" height="100"></canvas> 
 

 
      <p class="text-muted"><small>X:<span id="tooltipX">0</span> Y:<span id="tooltipY">0</span></small></p> 
 
      <br> 
 

 
      <h5>Output</h5> 
 
<pre> 
 
let sprite = SKSpriteNode(imageNamed: "codeImgName") 
 

 
let offsetX = sprite.size.width * sprite.anchorPoint.x 
 
let offsetY = sprite.size.height * sprite.anchorPoint.y 
 

 
let path = CGMutablePath() 
 

 
<span id="codeCGPath"></span> 
 
path.closeSubpath() 
 

 
sprite.physicsBody = SKPhysicsBody(polygonFromPath: path) 
 
</pre> 
 

 
     </div> 
 

 
     <script> 
 
// reference from http://davidwalsh.name/resize-image-canvas 
 

 
var spriteCanvas = document.getElementById('sprite'); 
 
var spriteContext = spriteCanvas.getContext('2d'); 
 
spriteContext.fillText('Drop Sprite Image Here', 400, 50); 
 

 
var pathCanvas = document.getElementById('path'); 
 
var pathContext = pathCanvas.getContext('2d'); 
 

 
function render(src){ 
 
    var image = new Image(); 
 
    image.onload = function(){ 
 
     spriteContext.clearRect(0, 0, spriteCanvas.width, spriteCanvas.height); 
 
     spriteCanvas.width = image.width; 
 
     spriteCanvas.height = image.height; 
 
     spriteContext.drawImage(image, 0, 0, image.width, image.height); 
 

 
     pathContext.clearRect(0, 0, pathCanvas.width, pathCanvas.height); 
 
     pathCanvas.width = image.width; 
 
     pathCanvas.height = image.height; 
 
    }; 
 
    image.src = src; 
 
} 
 

 
function loadImage(src){ 
 

 
    if(!src.type.match(/image.*/)){ 
 
     console.log('Dropped file is not image format'); 
 
     return; 
 
    } 
 

 
    var reader = new FileReader(); 
 
    reader.onload = function(e){ 
 
     render(e.target.result); 
 
    }; 
 
    reader.readAsDataURL(src); 
 

 
    var fileName = src.name; 
 
    var codeImgName = document.getElementById('codeImgName'); 
 
    codeImgName.innerHTML = fileName; 
 
} 
 

 
spriteCanvas.addEventListener('dragover', function(e){ 
 
    e.preventDefault(); 
 
}, true); 
 

 
spriteCanvas.addEventListener('drop', function(e){ 
 
    e.preventDefault(); 
 
    loadImage(e.dataTransfer.files[0]); 
 
}, true); 
 

 

 
var retinaMode = true; 
 
function toggleRetinaMode(){ 
 
    var status = document.getElementById('retinaCheckbox'); 
 

 
    retinaMode = status.checked ? true : false; 
 
} 
 

 

 

 
var actualX = 0; 
 
var actualY = 0; 
 
var displayX = document.getElementById('tooltipX'); 
 
var displayY = document.getElementById('tooltipY'); 
 

 
pathCanvas.onmousemove = function(e){ 
 
    actualX = e.pageX - this.offsetLeft; 
 
    actualY = e.pageY - this.offsetTop; 
 
    displayX.innerHTML = retinaMode ? Math.floor(actualX/2) : actualX; 
 
    displayY.innerHTML = retinaMode ? Math.floor((spriteCanvas.height - actualY - 1)/2) : spriteCanvas.height - actualY - 1; 
 
} 
 

 
var pathArray = new Array(); 
 
pathCanvas.onclick = function(e){ 
 
    var coor = { 
 
     actualX: actualX, 
 
     actualY: actualY, 
 
     displayX: displayX.innerHTML, 
 
     displayY: displayY.innerHTML, 
 
    }; 
 
    pathArray.push(coor); 
 
    refreshShape(pathArray); 
 
} 
 

 
var codeCGPath = document.getElementById('codeCGPath'); 
 
function refreshShape(pathArray){ 
 

 
    pathContext.clearRect(0, 0, pathCanvas.width, pathCanvas.height); 
 

 
    pathContext.beginPath(); 
 

 
    for(var i in pathArray){ 
 
     if(i == 0) { 
 
      pathContext.moveTo(pathArray[i].actualX, pathArray[i].actualY); 
 
      codeCGPath.innerHTML = 'path.move(to: CGPoint(x: '+pathArray[i].displayX+' - offsetX, y: '+pathArray[i].displayY+' - offsetY))<br>'; 
 
      continue; 
 
     } 
 
     pathContext.lineTo(pathArray[i].actualX, pathArray[i].actualY); 
 
     codeCGPath.innerHTML += 'path.addLine(to: CGPoint(x: '+pathArray[i].displayX+' - offsetX, y: '+pathArray[i].displayY+' - offsetY))<br>'; 
 
    } 
 

 
    pathContext.closePath(); 
 
    pathContext.lineWidth = 1; 
 
    pathContext.strokeStyle = 'blue'; 
 
    pathContext.stroke(); 
 
    pathContext.fillStyle = 'blue'; 
 
    pathContext.fill(); 
 
} 
 

 
function resetShape(){ 
 
    pathArray = new Array(); 
 
    codeCGPath.innerHTML = null; 
 
    pathContext.clearRect(0, 0, pathCanvas.width, pathCanvas.height); 
 
} 
 
     </script> 
 
    </body> 
 
</html>

Смежные вопросы